diff --git a/.kiro/specs/analytics-integration/requirements.md b/.kiro/specs/analytics-integration/requirements.md index 0a786355..b25b452c 100644 --- a/.kiro/specs/analytics-integration/requirements.md +++ b/.kiro/specs/analytics-integration/requirements.md @@ -6,22 +6,27 @@ > opt-out via `AnalyticsOptOut`. ## Status + **Superseded — do not implement** ## Summary + Integrates privacy-preserving telemetry and user consent tracking into the StellarForge frontend application following strict opt-in guidelines. ## Specifications & Requirements + 1. **Consent First**: Analytics telemetry MUST be disabled by default until explicit user opt-in consent is provided via CookieConsentBanner. 2. **Opt-Out & Bypass Protection**: Automated checks (`scripts/check-analytics-bypass.mjs`) must verify that telemetry cannot be triggered when consent is missing or revoked. 3. **ADR Alignment**: Privacy guarantees must conform to ADR-005 specifications. ## Implementation & Verification + - Privacy Architecture: `docs/adr/ADR-005-analytics-privacy-consent.md` - Telemetry Service: `frontend/src/services/analytics.ts` - React Hook & Consent: `frontend/src/hooks/useAnalytics.ts`, `frontend/src/components/CookieConsentBanner.tsx` - Automated Enforcement: `frontend/scripts/check-analytics-bypass.mjs` ## Related Issues + - Issue #1118: ADR-005's privacy guarantees have no traceable link to the code that implements them - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/cargo-lock-version-control/requirements.md b/.kiro/specs/cargo-lock-version-control/requirements.md index 599abf59..da34b11b 100644 --- a/.kiro/specs/cargo-lock-version-control/requirements.md +++ b/.kiro/specs/cargo-lock-version-control/requirements.md @@ -1,14 +1,18 @@ # Cargo Lock Version Control Spec ## Status + **Closed / Satisfied** ## Summary + The goal of tracking Rust contract lockfiles in version control is already satisfied in this repository. ## Verification & Implementation + - `contracts/Cargo.lock` is tracked in git. - Dependabot is configured in `.github/dependabot.yml` to automatically monitor and update Cargo dependencies. ## Related Issues + - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/changelog/requirements.md b/.kiro/specs/changelog/requirements.md index ac731d0e..ec95095b 100644 --- a/.kiro/specs/changelog/requirements.md +++ b/.kiro/specs/changelog/requirements.md @@ -1,19 +1,24 @@ # Changelog Automation Spec ## Status + **Shipped & Verified** ## Summary + Automate `CHANGELOG.md` updates from conventional commit messages during automated releases. ## Specifications & Shipped Functionality + 1. **Semantic Release Integration**: `.releaserc.json` includes `@semantic-release/changelog` and `@semantic-release/git`. 2. **Automated Commit & Release Notes**: On release, semantic-release generates release notes and updates `CHANGELOG.md` in root. 3. **Repository Tracked**: `CHANGELOG.md` is committed and up to date in repository root. ## Configuration References + - Release Config: `.releaserc.json` - Changelog File: `CHANGELOG.md` ## Related Issues + - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/eslint-import-order/requirements.md b/.kiro/specs/eslint-import-order/requirements.md index 71d71c66..604d56cd 100644 --- a/.kiro/specs/eslint-import-order/requirements.md +++ b/.kiro/specs/eslint-import-order/requirements.md @@ -1,18 +1,23 @@ # ESLint Import Order Spec ## Status + **Closed / Resolved** ## Summary + Spec for enforcing import ordering via ESLint plugin. ## Resolution & Rationale + - Code formatting and import organization are handled via Prettier (`.prettierrc`) and ESLint flat config (`frontend/eslint.config.js`). - Additional strict import ordering rules via `eslint-plugin-import` were evaluated and determined to be unneeded due to existing Prettier and TypeScript formatting workflows. ## Configuration References + - ESLint Flat Config: `frontend/eslint.config.js` - Prettier Config: `.prettierrc` ## Related Issues + - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/fee-display/requirements.md b/.kiro/specs/fee-display/requirements.md index b01bd2cb..327353be 100644 --- a/.kiro/specs/fee-display/requirements.md +++ b/.kiro/specs/fee-display/requirements.md @@ -37,26 +37,33 @@ Pre-signature fee display that shows the user the exact fee amount (in XLM + USD - A test asserts that the displayed total matches the `fee_payment` argument that will be submitted in the transaction. - A test covers the recipient breakdown when a fee split is configured. - A test covers the `count > 1` multiplier. + # Fee Display Spec ## Status + **Partially Shipped (Active Issue #1108)** ## Summary + Provide transparent, real-time fee breakdown and simulation before the user signs Soroban smart contract transactions. ## Current State & Shipped Code + - `FeeDisplay.tsx` component is partially implemented (`frontend/src/components/FeeDisplay.tsx`). - Basic fee estimation is displayed in certain UI components, but pre-signature fee breakdowns for complex Soroban invocation resource requirements (resource fee, network fee, inclusion fee) are missing. ## Requirements & Remaining Gaps + 1. **Pre-Signature Breakdown**: Show explicit breakdown of base fee, resource fee, and maximum transaction fee prior to Freighter wallet signature prompt. 2. **Dynamic Estimation**: Re-estimate fees dynamically when transaction parameters change. 3. **Error Feedback**: Present clear user notification when estimated fee exceeds account balance. ## Implementation References + - Component: `frontend/src/components/FeeDisplay.tsx` ## Related Issues + - Issue #1108: No pre-signature fee breakdown shown to users - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/invalid-parameters-validation/requirements.md b/.kiro/specs/invalid-parameters-validation/requirements.md index b8c0b8b1..bf711435 100644 --- a/.kiro/specs/invalid-parameters-validation/requirements.md +++ b/.kiro/specs/invalid-parameters-validation/requirements.md @@ -12,38 +12,45 @@ Drift detection via `scripts/check-validation-drift.sh` (CI: `.github/workflows/ ## Bounds (matching contract) -| Field | Max | Unit | -|----------|-------|---------| -| name | 32 | UTF-8 bytes | -| symbol | 12 | UTF-8 bytes | -| decimals | 18 | integer | +| Field | Max | Unit | +| -------- | --- | ----------- | +| name | 32 | UTF-8 bytes | +| symbol | 12 | UTF-8 bytes | +| decimals | 18 | integer | ## See Also - `contracts/token-factory/src/lib.rs`:749 — `validate_token_params` - `frontend/src/utils/validation.ts` — `validateTokenParams`, exported constants - `scripts/check-validation-drift.sh` — CI drift detection + # Invalid Parameters Validation Spec ## Status + **Shipped with Contract Divergences (Active Issue #1099)** ## Summary + Ensure rigorous parameter validation across Frontend, API, and Soroban Smart Contracts to prevent invalid token creation or parameter rejection. ## Current State & Shipped Code + - Frontend parameter validation implemented in `frontend/src/utils/validation.ts` and `frontend/src/components/CreateToken.tsx`. - API payload schema validation implemented in `api/_lib/schemaValidation.ts`. - Contract validation implemented in `contracts/token-factory/src/lib.rs`. ## Identified Divergences & Gaps + - Issue #1099 identifies divergence where frontend validation limits, regex patterns, or string length rules differ from the Soroban smart contract invariants. - Frontend and backend validation bounds must strictly match contract bounds. ## Requirements + 1. **Contract Parity**: Input validation rules in frontend/API must strictly mirror smart contract constraints. 2. **Immediate Feedback**: Display clear field-level error messages before submitting transactions. ## Related Issues + - Issue #1099: Frontend validation silently diverges from the contract in both directions - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/skeleton-loaders/requirements.md b/.kiro/specs/skeleton-loaders/requirements.md index 184bd894..304d0fa3 100644 --- a/.kiro/specs/skeleton-loaders/requirements.md +++ b/.kiro/specs/skeleton-loaders/requirements.md @@ -1,20 +1,25 @@ # Skeleton Loaders Spec ## Status + **Shipped & Verified** ## Summary + Provide standardized skeleton components to indicate asynchronous loading states throughout the application. ## Specifications & Shipped Functionality + 1. **UI Skeleton Component**: Reusable Tailwind-styled animated pulsing placeholder (`Skeleton.tsx`). 2. **Storybook Stories**: Documented variant loading states in Storybook (`Skeleton.stories.tsx`). 3. **Application Integration**: Used across main application flows including token dashboards, token detail views, and metadata cards. ## Implementation References + - Core Component: `frontend/src/components/UI/Skeleton.tsx` - Component Stories: `frontend/src/components/UI/Skeleton.stories.tsx` - Exports: `frontend/src/components/UI/index.ts` ## Related Issues + - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/soroban-token-sdk-audit/design.md b/.kiro/specs/soroban-token-sdk-audit/design.md index a956c049..00aa1f2b 100644 --- a/.kiro/specs/soroban-token-sdk-audit/design.md +++ b/.kiro/specs/soroban-token-sdk-audit/design.md @@ -23,12 +23,14 @@ A professional smart contract audit of `soroban_token_contract.wasm` (from `stel ### Option B: Document provenance and require explicit risk acceptance (chosen) Create `docs/token-wasm-provenance.md` that: + - Identifies the canonical upstream source - States the honest audit status (not independently audited by this project) - Provides a deployment log template so every deployer records their specific hash and decision - Links to the mainnet checklist item that enforces this before any production deploy This approach: + - Closes the unsourced "audited" claim gap immediately - Creates an enforceable gate in the deployment process - Provides an upgrade path when a future audit is completed @@ -41,6 +43,7 @@ This approach: ### `docs/token-wasm-provenance.md` Sections: + 1. **What is `token_wasm_hash`?** — explains the security dependency 2. **Upstream reference implementation** — table of source, SDK version, maintainer 3. **Audit status** — honest declaration of current state; explains what "well-reviewed" vs "audited" means diff --git a/.kiro/specs/soroban-token-sdk-audit/requirements.md b/.kiro/specs/soroban-token-sdk-audit/requirements.md index 36c7fb9d..2999791f 100644 --- a/.kiro/specs/soroban-token-sdk-audit/requirements.md +++ b/.kiro/specs/soroban-token-sdk-audit/requirements.md @@ -26,6 +26,7 @@ The factory references `soroban-token-sdk = "26.1.0"` for its own token interact ### REQ-01: Provenance documentation A document must exist in `docs/` that answers: + - What is the canonical source of the token WASM used by the factory? - Which upstream repository, version/tag, and commit does it come from? - What SDK version was it compiled against? @@ -35,6 +36,7 @@ A document must exist in `docs/` that answers: ### REQ-02: Deployment log template The provenance document must include a deployment log table for deployers to record: + - Network (testnet/mainnet) - Exact source tag/commit - Resulting WASM hash (hex) @@ -44,6 +46,7 @@ The provenance document must include a deployment log table for deployers to rec ### REQ-03: Checklist enforcement `docs/mainnet-deployment-checklist.md` must contain a specific line item requiring deployers to: + - Confirm the WASM provenance is documented - Confirm the WASM hash is recorded - Confirm the audit status or risk-acceptance decision is on file @@ -91,25 +94,31 @@ The audit gap was resolved by: 3. Confirming that `README.md` Step 4 (Upload Token Contract WASM) correctly qualifies the `soroban-examples` source with a pinned-tag requirement and a provenance notice — it does not make any unsourced "audited" claim. If a professional audit is subsequently commissioned, the report should be filed under `docs/audits/` and both `docs/token-wasm-provenance.md` and this spec should be updated to reflect the findings. + # Soroban Token SDK Security Audit Spec ## Status + **Scoped, Not Executed (Active Issue #1113)** ## Summary + Perform security audit and WASM verification for deployed Soroban Token Factory smart contracts and compiled WebAssembly binaries. ## Objectives & Scope + 1. **Bytecode Verification**: Verify target WASM bytecode hashes against source code compilations. 2. **Reentrancy & Authorization**: Audit administrative capability checks, authorization wrappers (`require_auth`), and fee distribution logic. 3. **Fuzzing & Property Tests**: Ensure fuzz targets in `contracts/token-factory/fuzz` achieve required coverage without panic conditions. 4. **WASM Optimization**: Enforce contract WASM binary size constraints. ## Related Artifacts & Tools + - Fuzzing suite: `contracts/token-factory/fuzz/` - Audit documentation: `docs/security-triage.md` - WASM verification workflow: `.github/workflows/wasm-verify.yml` ## Related Issues + - Issue #1113: The token-WASM security-audit spec was scoped and never executed or closed - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/soroban-token-sdk-audit/tasks.md b/.kiro/specs/soroban-token-sdk-audit/tasks.md index 1f0adad7..58d6fb0d 100644 --- a/.kiro/specs/soroban-token-sdk-audit/tasks.md +++ b/.kiro/specs/soroban-token-sdk-audit/tasks.md @@ -28,6 +28,7 @@ Resolved via Issue 25. See [`requirements.md`](./requirements.md) for context an ### Task 3 — Confirm README.md has no unsourced audit claims ✅ Step 4 in the deployment guide already contained the correct provenance notice: + - Pinned-tag instruction (do NOT use `main`) - Reference to `docs/token-wasm-provenance.md` - Explicit statement that the project has not commissioned an independent audit @@ -38,6 +39,7 @@ No unsourced "audited" claims found. No change required to README.md. ### Task 4 — Create `docs/token-wasm-provenance.md` ✅ Created [`docs/token-wasm-provenance.md`](../../docs/token-wasm-provenance.md) with: + - Explanation of the `token_wasm_hash` security dependency - Upstream source table (repository, path, interface, SDK version) - Honest audit status declaration @@ -68,14 +70,15 @@ See git history for commit details. ## Files changed -| File | Change | -|---|---| -| `docs/token-wasm-provenance.md` | Created — definitive provenance and audit status document | -| `docs/mainnet-deployment-checklist.md` | Updated — added WASM provenance audit line item | -| `README.md` | Already correct — no changes required | -| `.kiro/specs/soroban-token-sdk-audit/requirements.md` | Created — this spec's requirements | -| `.kiro/specs/soroban-token-sdk-audit/design.md` | Created — this spec's design | -| `.kiro/specs/soroban-token-sdk-audit/tasks.md` | Created — this file | +| File | Change | +| ----------------------------------------------------- | --------------------------------------------------------- | +| `docs/token-wasm-provenance.md` | Created — definitive provenance and audit status document | +| `docs/mainnet-deployment-checklist.md` | Updated — added WASM provenance audit line item | +| `README.md` | Already correct — no changes required | +| `.kiro/specs/soroban-token-sdk-audit/requirements.md` | Created — this spec's requirements | +| `.kiro/specs/soroban-token-sdk-audit/design.md` | Created — this spec's design | +| `.kiro/specs/soroban-token-sdk-audit/tasks.md` | Created — this file | + # Tasks: Soroban Token SDK Security Audit - [ ] 1. Execute full cargo-audit check on contracts workspace diff --git a/.kiro/specs/token-metadata-display/requirements.md b/.kiro/specs/token-metadata-display/requirements.md index e388ce74..c679c72b 100644 --- a/.kiro/specs/token-metadata-display/requirements.md +++ b/.kiro/specs/token-metadata-display/requirements.md @@ -1,20 +1,25 @@ # Token Metadata Display Spec ## Status + **Shipped & Verified** ## Summary + Display IPFS-hosted token metadata, including token logo image, name, symbol, and description with fallbacks and loading states. ## Specifications & Shipped Functionality + 1. **IPFS Image Retrieval**: Fetches IPFS metadata CIDs via IPFS gateway (`ipfsToGatewayUrl`). 2. **Skeleton & Fallbacks**: Displays circular skeleton loader while fetching, and fallback placeholder image when URI/metadata is missing or broken. 3. **Unit Tests**: Full test suite verifying loading, resolved, and placeholder states (`TokenMetadata.test.tsx`). ## Implementation References + - Component: `frontend/src/components/TokenMetadata.tsx` - Unit Test: `frontend/src/components/TokenMetadata.test.tsx` - Service: `frontend/src/services/ipfs.ts` ## Related Issues + - Issue #1117: Multiple `.kiro/specs` directories are abandoned stubs diff --git a/.kiro/specs/token-search-filter/design.md b/.kiro/specs/token-search-filter/design.md index a2631339..986e4e77 100644 --- a/.kiro/specs/token-search-filter/design.md +++ b/.kiro/specs/token-search-filter/design.md @@ -3,15 +3,18 @@ ## Architecture Decision: Client-Side vs Indexer-Backed Search ### Option A: Client-Side Full-Fetch-Then-Filter (CHOSEN FOR MVP) + **Approach**: Fetch all pages of tokens into client state, then filter locally by name/symbol/address. **Pros**: + - Simple: no API changes needed - Works immediately with existing `/api/tokens?creator=` pagination - Metadata (name, symbol) already cached in UI state after render - Composable with existing creator filter (both applied in memory) **Cons**: + - Doesn't scale beyond ~1000 tokens (each page load fetches 10-20 tokens, so ~100+ requests for 1000 tokens) - Wastes bandwidth fetching all pages even if user types a specific name - Client bears the cost of pagination traversal (keyset cursors required per page) @@ -19,14 +22,17 @@ **Decision Rationale**: The factory currently has <100 deployed tokens in testnet. A client-side implementation handles that envelope comfortably and can be deployed immediately. Once token count exceeds 1000 and/or the indexer is confirmed stable in production (issue #1090), we backfill to Option B with an `/api/tokens?search=` parameter (no breaking change). ### Option B: Indexer-Backed Search (Future M6) + **Approach**: Add `search` query parameter to `/api/tokens?search=` backed by Postgres full-text search or LIKE queries in postgresStore.ts. **Pros**: + - Scales to any token count - Server filters early, client receives only matches - Composable with existing `?creator=` filter **Cons**: + - Requires production indexer (blocked by #1090) - Adds database load (mitigated by caching, keyset pagination) - Adds API versioning complexity @@ -36,23 +42,25 @@ ## Implementation (MVP — Client-Side) ### State & Input Handling + ```typescript const [nameSymbolSearch, setNameSymbolSearch] = useState('') const debouncedNameSymbolSearch = useDebounce(nameSymbolSearch, 300) ``` ### Search Function + ```typescript const getFilteredTokens = (): TokenWithMetadata[] => { const creatorLower = debouncedCreatorFilter.toLowerCase() const searchLower = debouncedNameSymbolSearch.toLowerCase() - + return tokens.filter((t) => { // Creator filter (existing) if (creatorLower && t.creator && !t.creator.toLowerCase().includes(creatorLower)) { return false } - + // Name/symbol filter (new) if (searchLower) { const nameMatch = t.metadata?.name?.toLowerCase().includes(searchLower) ?? false @@ -60,13 +68,14 @@ const getFilteredTokens = (): TokenWithMetadata[] => { const addressMatch = t.address.toLowerCase().includes(searchLower) return nameMatch || symbolMatch || addressMatch } - + return true }) } ``` ### UI Components + - **Search Input**: Placed above the token list, styled consistently with existing creator filter - **Placeholder Text**: "Search by token name, symbol, or address..." - **Clear Button**: `x` icon to reset search @@ -74,15 +83,18 @@ const getFilteredTokens = (): TokenWithMetadata[] => { - **Empty State**: "No tokens match your search" distinct from "No tokens created yet" ### Metadata Handling + - Token name and symbol come from IPFS metadata (fetched via `getMetadata()`) - Fall back to address-only search if metadata fetch fails - Metadata cache already populated during list render via `enrichPage()` ### Composability + - Creator filter + name/symbol search are applied sequentially (both must match) - No radio-button "search OR filter" toggle; both are always active ## Migration Path to Option B (M6+) + 1. When indexer is production-ready, add `search` column(s) to Postgres schema 2. Update postgresStore.ts `listTokens()` to accept optional `search` parameter 3. Update API endpoint to accept `?search=` query param diff --git a/.kiro/specs/token-search-filter/requirements.md b/.kiro/specs/token-search-filter/requirements.md index 5c11571f..81e408d4 100644 --- a/.kiro/specs/token-search-filter/requirements.md +++ b/.kiro/specs/token-search-filter/requirements.md @@ -1,49 +1,63 @@ # Token Search & Filtering — Requirements ## Status + **In Progress (Issue #1107)** ## Problem Statement + TokenExplorer.tsx supports only: + - Creator address substring filtering (via `getFilteredTokens()`) - Exact token index or address lookup (via `handleSearch()`) There is no way to search tokens by name or symbol. This is a real usability gap preventing users from discovering tokens they're interested in. The frontend currently pages tokens client-side (getAllTokens), so a naive implementation would fetch every page before filtering — this does not scale as token count grows. The proper solution requires an architecture decision: + 1. **Client-side full-fetch-then-filter** (simple, immediate, doesn't scale beyond ~1000 tokens) 2. **Indexer-backed search** via new `/api/tokens?search=` query parameter (deferred until indexer is fully production-ready and issue #1090 is confirmed closed) ## Requirements + ### R1: Name & Symbol Search + Users can type a keyword to filter tokens by name or symbol (case-insensitive, substring match). ### R2: Creator Address Filtering (Existing) + Existing creator address filter continues to work and composes with name/symbol search (both applied simultaneously). ### R3: Debounced Input + Search input debounces at 300ms to avoid excessive renders or API calls. ### R4: Loading & Empty States + - **Loading state**: Show spinner while search is processing (relevant if indexer-backed) - **Empty state**: Clear message when no tokens match combined filters (distinct from "no tokens created yet") ### R5: Searchable Metadata + Search matches against: + - Token name (from IPFS metadata) - Token symbol (from IPFS metadata, if available) - Token contract address (exact or prefix match) ### R6: Architecture Documentation + Document the chosen approach (client-side vs indexer) and its scaling tradeoff in code comments or design notes. ## Out of Scope + - Server-side indexer search (deferred to M6 milestone once indexer is production-ready) - Advanced filter controls (paused/mintable state, custom properties) - Search history or saved filters - Token attributes beyond name/symbol/address ## Related Issues & Dependencies + - **Issue #1107**: Token Explorer has no name/symbol search (this feature) - **Issue #1090**: Indexer cron was never scheduled (RESOLVED in M1) - **Issue #1111**: Unused `.kiro/specs` stubs (requires backfilling this spec or removing it) diff --git a/.kiro/specs/token-search-filter/tasks.md b/.kiro/specs/token-search-filter/tasks.md index 666146be..1a9f7e9d 100644 --- a/.kiro/specs/token-search-filter/tasks.md +++ b/.kiro/specs/token-search-filter/tasks.md @@ -1,12 +1,14 @@ # Tasks: Token Search & Filtering (MVP — Client-Side) ## Task 1: Add Search State & Input Handler + - [ ] 1.1 Add `nameSymbolSearch` state and setter to TokenExplorer.tsx - [ ] 1.2 Create `debouncedNameSymbolSearch` using existing `useDebounce` hook (300ms) - [ ] 1.3 Add input change handler that updates `nameSymbolSearch` state - [ ] 1.4 Verify debouncing prevents excessive re-renders (test with React DevTools) ## Task 2: Implement Client-Side Name/Symbol Filter Logic + - [ ] 2.1 Refactor `getFilteredTokens()` to apply both creator AND name/symbol filters - [ ] 2.2 Filter matches name field case-insensitively (substring match) - [ ] 2.3 Filter matches symbol field case-insensitively (substring match) @@ -16,6 +18,7 @@ - [ ] 2.7 Fallback gracefully when metadata is unavailable (use address-only search) ## Task 3: Add Search UI Components + - [ ] 3.1 Add search input field above the token list - [ ] 3.2 Placeholder text: "Search by token name, symbol, or address..." - [ ] 3.3 Add clear button (×) that resets search when clicked @@ -24,6 +27,7 @@ - [ ] 3.6 Update empty state message: distinguish "no matches" from "no tokens exist" ## Task 4: Add Loading & Empty State UX + - [ ] 4.1 Show spinner while search is debouncing (optional, high polish) - [ ] 4.2 Show distinct empty state when no tokens match filters - [ ] 4.3 Empty state has clear call-to-action: "Clear search" or "Browse all tokens" @@ -31,6 +35,7 @@ - [ ] 4.5 Pagination still works while search is active (user can page through filtered results) ## Task 5: Write Tests + - [ ] 5.1 Test exact name match (case-insensitive) - [ ] 5.2 Test partial/substring name match - [ ] 5.3 Test symbol match (case-insensitive) @@ -44,12 +49,14 @@ - [ ] 5.11 Test metadata unavailable fallback (search by address only) ## Task 6: Documentation & Architecture Note + - [ ] 6.1 Add code comment in `getFilteredTokens()` explaining client-side architecture choice - [ ] 6.2 Document scaling tradeoff: "Client-side search scales to ~1000 tokens" - [ ] 6.3 Add TODO comment linking to M6 migration path (Option B: indexer-backed search) - [ ] 6.4 Update ISSUES.md: close issue #1107, reference this spec, link to follow-up M6 task ## Acceptance Criteria (All Must Pass) + - ✅ Users can search tokens by name (case-insensitive, substring) - ✅ Users can search tokens by symbol (case-insensitive, substring) - ✅ Users can search tokens by contract address diff --git a/CHANGELOG.md b/CHANGELOG.md index 74cf1426..22baa0ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,810 +1,776 @@ ## [1.8.2](https://github.com/Favourorg/Stellar-forge/compare/v1.8.1...v1.8.2) (2026-08-25) - ### Bug Fixes -* **ci:** resolve access-control workflow triggers, ipfs cid validation, and test suites drift ([#1171](https://github.com/Favourorg/Stellar-forge/issues/1171)) ([da7930d](https://github.com/Favourorg/Stellar-forge/commit/da7930d89f1cf303038c4c35010316ca8c211614)) +- **ci:** resolve access-control workflow triggers, ipfs cid validation, and test suites drift ([#1171](https://github.com/Favourorg/Stellar-forge/issues/1171)) ([da7930d](https://github.com/Favourorg/Stellar-forge/commit/da7930d89f1cf303038c4c35010316ca8c211614)) # 1.0.0 (2026-08-24) -## [1.8.1](https://github.com/Favourorg/Stellar-forge/compare/v1.8.0...v1.8.1) (2026-08-25) +## [1.8.1](https://github.com/Favourorg/Stellar-forge/compare/v1.8.0...v1.8.1) (2026-08-25) ### Bug Fixes -* [#741](https://github.com/ignaciojulio/Stellar-forge/issues/741) AdminPanel restricted to admin address only ([7b2b8c2](https://github.com/ignaciojulio/Stellar-forge/commit/7b2b8c23d40955b39ea300acea24cfeef851d32d)) -* **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1036](https://github.com/ignaciojulio/Stellar-forge/issues/1036)) ([e3174cb](https://github.com/ignaciojulio/Stellar-forge/commit/e3174cb0bde98950c3bf7be8b97beb16a8cd8113)), closes [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) -* **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1037](https://github.com/ignaciojulio/Stellar-forge/issues/1037)) ([116d025](https://github.com/ignaciojulio/Stellar-forge/commit/116d0258ba1a58cfb22f5a12de9107b00e0323d5)), closes [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) -* **#854:** format useTransactionHistory.ts to match project Prettier style (remove semicolons) ([8e7b12b](https://github.com/ignaciojulio/Stellar-forge/commit/8e7b12b757780a3570ec5b425ba61bcf4a23d6b1)), closes [#854](https://github.com/ignaciojulio/Stellar-forge/issues/854) -* **#855:** eliminate CSP duplication by generating index.html meta tag from policy.ts ([1dc325a](https://github.com/ignaciojulio/Stellar-forge/commit/1dc325a503f0f41eb78e5220e1252b4afcb5ee13)), closes [#855](https://github.com/ignaciojulio/Stellar-forge/issues/855) -* **#932:** consolidate useTransactionPolling into useTransaction.ts ([#956](https://github.com/ignaciojulio/Stellar-forge/issues/956)) ([28a84b6](https://github.com/ignaciojulio/Stellar-forge/commit/28a84b67df80e8f6c155e97da6f54704a36113cb)), closes [#932](https://github.com/ignaciojulio/Stellar-forge/issues/932) [#932](https://github.com/ignaciojulio/Stellar-forge/issues/932) -* **#944:** add txHash, network, contractId Sentry tagging on transaction failures ([#952](https://github.com/ignaciojulio/Stellar-forge/issues/952)) ([9c213d0](https://github.com/ignaciojulio/Stellar-forge/commit/9c213d09b089f5704d2748ccc7e3aa2b4fc18a15)), closes [#944](https://github.com/ignaciojulio/Stellar-forge/issues/944) [#944](https://github.com/ignaciojulio/Stellar-forge/issues/944) -* **#945:** document batch resource limits and add frontend size cap ([#953](https://github.com/ignaciojulio/Stellar-forge/issues/953)) ([8555f65](https://github.com/ignaciojulio/Stellar-forge/commit/8555f65acc16ff60cd3108eb533d836ca7fcd0f2)), closes [#945](https://github.com/ignaciojulio/Stellar-forge/issues/945) [#945](https://github.com/ignaciojulio/Stellar-forge/issues/945) -* **#947:** add incident response runbook and break-glass recovery docs ([#954](https://github.com/ignaciojulio/Stellar-forge/issues/954)) ([0546342](https://github.com/ignaciojulio/Stellar-forge/commit/054634208dd995ce8daacbd83199c6c8e3547c2a)), closes [#947](https://github.com/ignaciojulio/Stellar-forge/issues/947) [#9](https://github.com/ignaciojulio/Stellar-forge/issues/9) [#947](https://github.com/ignaciojulio/Stellar-forge/issues/947) -* accept decimals=0 in validateTokenParams ([56cb8d9](https://github.com/ignaciojulio/Stellar-forge/commit/56cb8d961c2d5e421f5391b6d31587ad52013d4b)) -* add bounds validation to token metadata type guard (CWE-1236) ([#964](https://github.com/ignaciojulio/Stellar-forge/issues/964)) ([ab4cb5c](https://github.com/ignaciojulio/Stellar-forge/commit/ab4cb5c31ea6ded2673ee8d4dc61d11f2469d5a7)) -* add BurnAmountExceedsBalance check in burn function ([1113068](https://github.com/ignaciojulio/Stellar-forge/commit/1113068ceb02e464c40066021ca24279dc4753ab)) -* add CI drift check for contract ABI documentation - Closes [#946](https://github.com/ignaciojulio/Stellar-forge/issues/946) ([#949](https://github.com/ignaciojulio/Stellar-forge/issues/949)) ([8e67454](https://github.com/ignaciojulio/Stellar-forge/commit/8e67454a4a4d41c8fe1232eb0d2faebce79f9c6d)) -* add env var validation and misconfiguration screen ([f66f1d5](https://github.com/ignaciojulio/Stellar-forge/commit/f66f1d5c144e9e96ddb451e4feeffca41e950b3d)) -* add esbuild as a direct devDependency for Storybook CI build ([512b11e](https://github.com/ignaciojulio/Stellar-forge/commit/512b11e8cad65979e4fbbdac073ddb8dc5ba1fa8)) -* add formula-injection guard to CSV export (CWE-1236) ([#963](https://github.com/ignaciojulio/Stellar-forge/issues/963)) ([bff7012](https://github.com/ignaciojulio/Stellar-forge/commit/bff70125f81172ece961c8c4f9f2a215e6f746ce)) -* add missing build step to E2E job, fix sitemap script crash ([535955c](https://github.com/ignaciojulio/Stellar-forge/commit/535955c34bbd6b3877fde7f5a29b42288352cdcc)) -* add missing imports for mobile responsive components ([0b89740](https://github.com/ignaciojulio/Stellar-forge/commit/0b89740d64d35bfacddd14b8c6b5a7c4933a4c7b)) -* add standalone network support and fix E2E test mocks ([a78f8de](https://github.com/ignaciojulio/Stellar-forge/commit/a78f8deef5c21e74f3b391726a60636692a242c3)) -* align adm_upd topic and add CI drift detection ([#1032](https://github.com/ignaciojulio/Stellar-forge/issues/1032)) ([872baa9](https://github.com/ignaciojulio/Stellar-forge/commit/872baa9047675607156a731e1c9de78d4e9843fb)) -* align frontend token validation with contract (name ≤ 32 UTF-8 bytes, remove ASCII-only restriction) ([#1125](https://github.com/ignaciojulio/Stellar-forge/issues/1125)) ([cefa9b9](https://github.com/ignaciojulio/Stellar-forge/commit/cefa9b9c13bbc7f2b5a770e5376369c4875c3833)) -* **analytics:** add opt-out tests, CI bypass check, and compliance ADR ([#965](https://github.com/ignaciojulio/Stellar-forge/issues/965)) ([180f672](https://github.com/ignaciojulio/Stellar-forge/commit/180f6725d2f82fa5a068687e428886e85179edd3)), closes [#948](https://github.com/ignaciojulio/Stellar-forge/issues/948) -* **api:** add rate limiting to auth challenge endpoints ([#1144](https://github.com/ignaciojulio/Stellar-forge/issues/1144)) ([600e8a0](https://github.com/ignaciojulio/Stellar-forge/commit/600e8a057f98129ad93a520030c3224682da0400)), closes [#1101](https://github.com/ignaciojulio/Stellar-forge/issues/1101) -* **api:** remove clientIp() dead code with inverted XFF parsing (audit [#26](https://github.com/ignaciojulio/Stellar-forge/issues/26)) ([#1129](https://github.com/ignaciojulio/Stellar-forge/issues/1129)) ([fa1a888](https://github.com/ignaciojulio/Stellar-forge/commit/fa1a888c99133d2fafab52f3e79444d1ac188766)), closes [#1101](https://github.com/ignaciojulio/Stellar-forge/issues/1101) -* **api:** sanitize lastError in health/indexer to avoid leaking internal error details ([#1143](https://github.com/ignaciojulio/Stellar-forge/issues/1143)) ([c51d179](https://github.com/ignaciojulio/Stellar-forge/commit/c51d179b782507f167150b719309715fcf6225d9)), closes [#1103](https://github.com/ignaciojulio/Stellar-forge/issues/1103) -* **api:** store wallet-auth challenges in Vercel KV (Closes [#1091](https://github.com/ignaciojulio/Stellar-forge/issues/1091)) ([#1132](https://github.com/ignaciojulio/Stellar-forge/issues/1132)) ([62941bb](https://github.com/ignaciojulio/Stellar-forge/commit/62941bb0131970c10fc56f5fcf19135eefe8de3f)) -* audit follow-ups — restore tx polling backoff, fix wasm target, drop orphan form ([05409eb](https://github.com/ignaciojulio/Stellar-forge/commit/05409eb55f4e3ff2797fce06d631fc94553a0239)), closes [#852](https://github.com/ignaciojulio/Stellar-forge/issues/852) [#732](https://github.com/ignaciojulio/Stellar-forge/issues/732) [813/#814](https://github.com/ignaciojulio/Stellar-forge/issues/814) -* **build:** build the contract for wasm32v1-none everywhere ([#940](https://github.com/ignaciojulio/Stellar-forge/issues/940)) ([0aa6df3](https://github.com/ignaciojulio/Stellar-forge/commit/0aa6df38bc25e5bf1941a7dbbafd12616a108505)) -* **ci:** remove continue-on-error from fuzz steps, add PR smoke job ([#937](https://github.com/ignaciojulio/Stellar-forge/issues/937)) ([#966](https://github.com/ignaciojulio/Stellar-forge/issues/966)) ([000458f](https://github.com/ignaciojulio/Stellar-forge/commit/000458f8ffde77f136476ea37f2758169f212e07)) -* clear cargo clippy -D warnings findings in token-factory ([2a27a8f](https://github.com/ignaciojulio/Stellar-forge/commit/2a27a8fff3e0b78b5173696166315c1470211a09)) -* complete contract test suite with all error variants covered ([5f8320d](https://github.com/ignaciojulio/Stellar-forge/commit/5f8320d7b14d3a93339ed3f82779d4763a0717b7)) -* **contract:** close open-proxy hole in burn ([#1021](https://github.com/ignaciojulio/Stellar-forge/issues/1021)) ([#1059](https://github.com/ignaciojulio/Stellar-forge/issues/1059)) ([895a621](https://github.com/ignaciojulio/Stellar-forge/commit/895a6218340f8540b8f961ddf47551c96f1c1dbc)) -* **contract:** front-load batch validation and document Soroban transaction atomicity ([#915](https://github.com/ignaciojulio/Stellar-forge/issues/915)) ([#974](https://github.com/ignaciojulio/Stellar-forge/issues/974)) ([b60868f](https://github.com/ignaciojulio/Stellar-forge/commit/b60868f0363e8e6c1c89927cfee42fecef7af34a)) -* **contracts:** add crash-to-regression-test process with fuzz corpus infrastructure ([#951](https://github.com/ignaciojulio/Stellar-forge/issues/951)) ([9428b7d](https://github.com/ignaciojulio/Stellar-forge/commit/9428b7d209366e9ba62ef72359c902cf9beb79b3)), closes [#938](https://github.com/ignaciojulio/Stellar-forge/issues/938) -* **contracts:** add distribute_fee test coverage at realistic split sizes ([#918](https://github.com/ignaciojulio/Stellar-forge/issues/918)) ([#1025](https://github.com/ignaciojulio/Stellar-forge/issues/1025)) ([f9ec953](https://github.com/ignaciojulio/Stellar-forge/commit/f9ec95316a5ee9968094f12947f7a088cd2b24d1)), closes [#919](https://github.com/ignaciojulio/Stellar-forge/issues/919) -* **contracts:** add integer overflow protection in fee arithmetic ([18622f1](https://github.com/ignaciojulio/Stellar-forge/commit/18622f1777201ba92c4db2ef60928faa4c053de3)), closes [#513](https://github.com/ignaciojulio/Stellar-forge/issues/513) -* **contracts:** charge exactly the required fee, not fee_payment ([#1035](https://github.com/ignaciojulio/Stellar-forge/issues/1035)) ([8654767](https://github.com/ignaciojulio/Stellar-forge/commit/86547670d6b45bf9a967ea59e26813b2670de6b5)), closes [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) [#1008](https://github.com/ignaciojulio/Stellar-forge/issues/1008) [#1008](https://github.com/ignaciojulio/Stellar-forge/issues/1008) -* **contracts:** close remaining FWC26 audit issues ([787dc22](https://github.com/ignaciojulio/Stellar-forge/commit/787dc22d4272d0258856b6a31967c164dcefddda)), closes [909-#948](https://github.com/909-/issues/948) [#1022](https://github.com/ignaciojulio/Stellar-forge/issues/1022) [#910](https://github.com/ignaciojulio/Stellar-forge/issues/910) [#913](https://github.com/ignaciojulio/Stellar-forge/issues/913) [#916](https://github.com/ignaciojulio/Stellar-forge/issues/916) [#943](https://github.com/ignaciojulio/Stellar-forge/issues/943) -* **contracts:** enforce MAX_BATCH_SIZE cap in create_tokens_batch (Closes [#1100](https://github.com/ignaciojulio/Stellar-forge/issues/1100)) ([#1135](https://github.com/ignaciojulio/Stellar-forge/issues/1135)) ([2ba33e5](https://github.com/ignaciojulio/Stellar-forge/commit/2ba33e5e5516b2e3e66388ebd3dcb4568a3b5a14)) -* **contracts:** fuzz the real burn entrypoint, not a reimplementation ([#1098](https://github.com/ignaciojulio/Stellar-forge/issues/1098)) ([#1137](https://github.com/ignaciojulio/Stellar-forge/issues/1137)) ([be8a342](https://github.com/ignaciojulio/Stellar-forge/commit/be8a3424d514423f9946635ff899440911bd3377)) -* **contracts:** make token-factory initialize atomic with deployment ([#1029](https://github.com/ignaciojulio/Stellar-forge/issues/1029)) ([3e12de2](https://github.com/ignaciojulio/Stellar-forge/commit/3e12de21ff69c7998ff0ad591bc8f066009e364f)), closes [#1005](https://github.com/ignaciojulio/Stellar-forge/issues/1005) -* **contracts:** move per-token bookkeeping to persistent storage ([#1034](https://github.com/ignaciojulio/Stellar-forge/issues/1034)) ([51c52bd](https://github.com/ignaciojulio/Stellar-forge/commit/51c52bd1bcb07eeda1744cd99f82a2816db6aa27)), closes [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) -* **contracts:** prove multi-step migrate pattern with synthetic v2 tests ([#919](https://github.com/ignaciojulio/Stellar-forge/issues/919)) ([#1026](https://github.com/ignaciojulio/Stellar-forge/issues/1026)) ([f9ef384](https://github.com/ignaciojulio/Stellar-forge/commit/f9ef3849f30d7af08473cd66268c0692def6da91)), closes [#918](https://github.com/ignaciojulio/Stellar-forge/issues/918) [#918](https://github.com/ignaciojulio/Stellar-forge/issues/918) -* **contracts:** repair broken merge artifacts on main ([#1041](https://github.com/ignaciojulio/Stellar-forge/issues/1041)) ([6524e58](https://github.com/ignaciojulio/Stellar-forge/commit/6524e58d86b00235622cb07e89d30a756df69f8e)), closes [1034/#1035](https://github.com/ignaciojulio/Stellar-forge/issues/1035) [#1033](https://github.com/ignaciojulio/Stellar-forge/issues/1033) [#1034](https://github.com/ignaciojulio/Stellar-forge/issues/1034) [#1025](https://github.com/ignaciojulio/Stellar-forge/issues/1025) -* **contracts:** seed max-supply counter with initial_supply ([#1006](https://github.com/ignaciojulio/Stellar-forge/issues/1006)) ([#1031](https://github.com/ignaciojulio/Stellar-forge/issues/1031)) ([4a3e90d](https://github.com/ignaciojulio/Stellar-forge/commit/4a3e90de113d45a28f67c765c4a7c07af38c7e44)) -* correct useLocalStorage syntax error and variable reference ([232fc52](https://github.com/ignaciojulio/Stellar-forge/commit/232fc520e4df8a4d1345e67e05084ae32252fe5e)) -* dedupe token-validation rules in validation.ts ([d3012c2](https://github.com/ignaciojulio/Stellar-forge/commit/d3012c2c310f31135a463f13482af36ec9b1dc46)), closes [#845](https://github.com/ignaciojulio/Stellar-forge/issues/845) -* **deps:** add Dependabot fuzz coverage and auto-merge policy ([#985](https://github.com/ignaciojulio/Stellar-forge/issues/985)) ([2247b9f](https://github.com/ignaciojulio/Stellar-forge/commit/2247b9f0cb3343708d5eebb461280d7e558a5b38)), closes [#941](https://github.com/ignaciojulio/Stellar-forge/issues/941) -* downgrade vite to v6 for Storybook compatibility ([c2f071b](https://github.com/ignaciojulio/Stellar-forge/commit/c2f071bb75ced96669d27f11cec13e11d9c83358)) -* **e2e:** add token-list-container class and show 6 trailing address chars ([9fcfff3](https://github.com/ignaciojulio/Stellar-forge/commit/9fcfff3398df79dd9ad987ff4ad51d15409f78b6)) -* **e2e:** prevent watcher auto-connect by not responding to REQUEST_NETWORK_DETAILS ([9649702](https://github.com/ignaciojulio/Stellar-forge/commit/9649702d0793d0e489bb9eb2caba0217f3ab99dc)) -* exclude fuzz crate from workspace to prevent wasm32 compilation errors ([b3f09f2](https://github.com/ignaciojulio/Stellar-forge/commit/b3f09f208486b314a10fd2f8061b90631fa5df3a)) -* expand .gitignore to prevent accidental commits of local artifacts ([1da56fe](https://github.com/ignaciojulio/Stellar-forge/commit/1da56fe00394ccbbff2a86d0de8fa7cf24356924)), closes [#835](https://github.com/ignaciojulio/Stellar-forge/issues/835) -* **explorer:** snapshot tokenCount once per session to prevent pagination drift ([#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126)) ([a27f77b](https://github.com/ignaciojulio/Stellar-forge/commit/a27f77b8dda5b76feced0cf6baeac7a42a84bcf0)) -* **frontend:** clear typecheck errors and prettier drift masked by red CI ([82994b9](https://github.com/ignaciojulio/Stellar-forge/commit/82994b977781c0b616e68b29fa1e1859765b0ac9)) -* **frontend:** close network-mismatch signing window with a fresh pre-sign check ([#961](https://github.com/ignaciojulio/Stellar-forge/issues/961)) ([7619e99](https://github.com/ignaciojulio/Stellar-forge/commit/7619e9960d68ad73f6fb67ee0f4f9d11d6ee6ba6)), closes [#927](https://github.com/ignaciojulio/Stellar-forge/issues/927) -* **frontend:** close unclosed PR wrapper in App.tsx and remove duplicate route entries ([4f9442b](https://github.com/ignaciojulio/Stellar-forge/commit/4f9442bda20864966521c36f1ed4272c52f56dd2)) -* **frontend:** establish transaction reconciliation policy and add phantom-entry guards ([#955](https://github.com/ignaciojulio/Stellar-forge/issues/955)) ([1372af1](https://github.com/ignaciojulio/Stellar-forge/commit/1372af165a869a1814ef9b43d22c9e9f507190f2)), closes [#933](https://github.com/ignaciojulio/Stellar-forge/issues/933) -* **frontend:** filter-aware cache key, stable useCallback deps, re-fetch on filter change ([62d2c8c](https://github.com/ignaciojulio/Stellar-forge/commit/62d2c8c3aaba49c1099b30db5e3956747b407b9a)) -* **frontend:** fix Option encoding, map missing topics, add cap field ([fb3ee73](https://github.com/ignaciojulio/Stellar-forge/commit/fb3ee73daa47161d932d9f91585762223afa6a1a)), closes [#1022](https://github.com/ignaciojulio/Stellar-forge/issues/1022) [#917](https://github.com/ignaciojulio/Stellar-forge/issues/917) [#1022](https://github.com/ignaciojulio/Stellar-forge/issues/1022) [#943](https://github.com/ignaciojulio/Stellar-forge/issues/943) -* **frontend:** handle every sendTransaction status explicitly ([#1020](https://github.com/ignaciojulio/Stellar-forge/issues/1020)) ([#1058](https://github.com/ignaciojulio/Stellar-forge/issues/1058)) ([70ebab6](https://github.com/ignaciojulio/Stellar-forge/commit/70ebab62bea7d7dc887e3ce6852a7f436b023083)), closes [#1056](https://github.com/ignaciojulio/Stellar-forge/issues/1056) [#1057](https://github.com/ignaciojulio/Stellar-forge/issues/1057) -* **frontend:** implement the CSV formula-injection guard its tests expected ([59839b6](https://github.com/ignaciojulio/Stellar-forge/commit/59839b603cf7a84d782a740ff455e9bc9748ed62)), closes [#963](https://github.com/ignaciojulio/Stellar-forge/issues/963) -* **frontend:** make token-detail routes public for deep links ([#880](https://github.com/ignaciojulio/Stellar-forge/issues/880)) ([971e14b](https://github.com/ignaciojulio/Stellar-forge/commit/971e14b24097a4f08688b097225728ed22955c6e)) -* **frontend:** only mount OnboardingModal on Help click, not first-visit ([87d3ce4](https://github.com/ignaciojulio/Stellar-forge/commit/87d3ce41a764067f90f0384ce795f6111fdcaeec)) -* **frontend:** paginate factory event fetch instead of silently capping "all tokens" ([#962](https://github.com/ignaciojulio/Stellar-forge/issues/962)) ([b480f56](https://github.com/ignaciojulio/Stellar-forge/commit/b480f56b8f935802aab26d2384efcb3eb3da9080)), closes [#35](https://github.com/ignaciojulio/Stellar-forge/issues/35) -* **frontend:** pay real base_fee, surface FeeDisplay in mint, block writes on network mismatch ([6d5697d](https://github.com/ignaciojulio/Stellar-forge/commit/6d5697d3f661be16c4fefccdb1a71f5b5d35734b)) -* **frontend:** remove exhaustive-deps suppressions, fix dep arrays ([a8fcf34](https://github.com/ignaciojulio/Stellar-forge/commit/a8fcf3463afe36bacf28f5f1f259eb5f8e7ca845)) -* **frontend:** resolve merge fallout — format, getMetadata validation, no-this-alias ([4e0d770](https://github.com/ignaciojulio/Stellar-forge/commit/4e0d77063f0d8b10f23cc9176ea2217bf9337b08)) -* **frontend:** resolve token identity from contract, not events ([#1018](https://github.com/ignaciojulio/Stellar-forge/issues/1018)) ([#1030](https://github.com/ignaciojulio/Stellar-forge/issues/1030)) ([66bcb19](https://github.com/ignaciojulio/Stellar-forge/commit/66bcb1915e5199371a1b49f5b353e0aba0dfd86a)) -* **frontend:** source FeeDisplay fees from useFactoryState, not the singleton ([e388e7a](https://github.com/ignaciojulio/Stellar-forge/commit/e388e7aacaf66708e01aba263121bd9b932895b2)) -* **frontend:** stop passing a decimal XLM string to formatXLM ([d23be61](https://github.com/ignaciojulio/Stellar-forge/commit/d23be616d378af583289ce5544de20673eeb5fda)) -* **frontend:** track Horizon paging_token and pass cursor on load-more ([aa6e15b](https://github.com/ignaciojulio/Stellar-forge/commit/aa6e15b235bda5842fed1e8aa5848a2e06b04959)) -* **frontend:** unify transaction poll backoff into shared utility ([#960](https://github.com/ignaciojulio/Stellar-forge/issues/960)) ([2ad85fc](https://github.com/ignaciojulio/Stellar-forge/commit/2ad85fc7f43c40a66746519eccaf89cb5147e53c)) -* **frontend:** wire orphaned features, fix standalone network, add typecheck gate ([c14d1b1](https://github.com/ignaciojulio/Stellar-forge/commit/c14d1b108ef210ede1d007f231cd4797f844fe26)) -* **infra:** consolidate vercel.json security headers (Closes [#1104](https://github.com/ignaciojulio/Stellar-forge/issues/1104)) ([#1134](https://github.com/ignaciojulio/Stellar-forge/issues/1134)) ([fc64bea](https://github.com/ignaciojulio/Stellar-forge/commit/fc64bea1d5185c43fe289214857246bfe014e51c)) -* **infra:** schedule the indexer cron in vercel.json (Closes [#1090](https://github.com/ignaciojulio/Stellar-forge/issues/1090)) ([#1130](https://github.com/ignaciojulio/Stellar-forge/issues/1130)) ([288d5f3](https://github.com/ignaciojulio/Stellar-forge/commit/288d5f3b1208405fd08e12342fef2ae58cf25a7b)), closes [#1123](https://github.com/ignaciojulio/Stellar-forge/issues/1123) [#1124](https://github.com/ignaciojulio/Stellar-forge/issues/1124) [#1125](https://github.com/ignaciojulio/Stellar-forge/issues/1125) [#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126) [#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126) [#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126) [#1121](https://github.com/ignaciojulio/Stellar-forge/issues/1121) [#1121](https://github.com/ignaciojulio/Stellar-forge/issues/1121) -* **ipfs:** retry image upload on transient Pinata errors ([26a2005](https://github.com/ignaciojulio/Stellar-forge/commit/26a2005ebfbe5c27c7f132c3f0a031d5c750ac30)), closes [#743](https://github.com/ignaciojulio/Stellar-forge/issues/743) -* **ipfs:** validate getMetadata response shape before returning ([7183346](https://github.com/ignaciojulio/Stellar-forge/commit/71833467e8e0aa7c8a770d2905056227e721378c)), closes [#849](https://github.com/ignaciojulio/Stellar-forge/issues/849) -* isolate per-recipient fee-split transfer failures from aborting the call ([#1136](https://github.com/ignaciojulio/Stellar-forge/issues/1136)) ([6e68f0d](https://github.com/ignaciojulio/Stellar-forge/commit/6e68f0d78f1272fa6a31cc6d8cb54859dc9fb83b)) -* make all 202 tests pass ([1043432](https://github.com/ignaciojulio/Stellar-forge/commit/1043432dcdf6307385661d7261fd8f73bcae6923)) -* pin esbuild/globals devDeps and apply npm audit fixes ([6ccd8c3](https://github.com/ignaciojulio/Stellar-forge/commit/6ccd8c3418b8617052bd8c290231cabad9d82119)) -* provide VITE_TOKEN_WASM_HASH in E2E CI job ([64c1a5b](https://github.com/ignaciojulio/Stellar-forge/commit/64c1a5b24f90f4685b1690b8653e620768924240)) -* real bugs surfaced while restoring lint/test coverage ([8434f56](https://github.com/ignaciojulio/Stellar-forge/commit/8434f5688c3f8877513c5931eef26bf93b85091f)) -* reclaim orphaned IPFS pins on failed set_metadata (Closes [#1096](https://github.com/ignaciojulio/Stellar-forge/issues/1096)) ([#1146](https://github.com/ignaciojulio/Stellar-forge/issues/1146)) ([d845880](https://github.com/ignaciojulio/Stellar-forge/commit/d84588094a620097ffcb3d66135201ffedc70ad8)) -* redesign fee transfer and token deployment per issue spec ([e7b8c9e](https://github.com/ignaciojulio/Stellar-forge/commit/e7b8c9e7f0a77cb618b39afa0b91ea6ac87c5b21)) -* refactor build system, fix contract errors, fix dark mode toggle ([85751f8](https://github.com/ignaciojulio/Stellar-forge/commit/85751f85239640acbae8197feccb14ff63724c16)) -* relabel TokenDetail Admin field to 'Deployed by' (Closes [#1109](https://github.com/ignaciojulio/Stellar-forge/issues/1109)) ([#1119](https://github.com/ignaciojulio/Stellar-forge/issues/1119)) ([5d5df07](https://github.com/ignaciojulio/Stellar-forge/commit/5d5df075612a6e510448e17087c281d987a36478)) -* **release:** add @actions/io to satisfy @actions/exec's undeclared import ([cd21fdc](https://github.com/ignaciojulio/Stellar-forge/commit/cd21fdc70110759165e95d85803d48f15dd7225f)) -* **release:** disable husky hooks in the release workflow ([5429060](https://github.com/ignaciojulio/Stellar-forge/commit/5429060a58cf30265f835f3954a420de043452df)) -* remove 'unsafe-inline' from CSP style-src (Closes [#1105](https://github.com/ignaciojulio/Stellar-forge/issues/1105)) ([#1123](https://github.com/ignaciojulio/Stellar-forge/issues/1123)) ([838129c](https://github.com/ignaciojulio/Stellar-forge/commit/838129ccc63f862350ac86ee1efcc1ba2ae4a163)) -* repair local Stellar network startup in E2E CI job ([5aa9026](https://github.com/ignaciojulio/Stellar-forge/commit/5aa90265077404369cfe81c6a96eb94017075893)) -* replace console.error with logger in CreateToken, TokenForm, MetadataUploadForm ([24805af](https://github.com/ignaciojulio/Stellar-forge/commit/24805af56b93e60392a4817ba8708c29960dd043)), closes [#848](https://github.com/ignaciojulio/Stellar-forge/issues/848) -* replace invalid checksum address in validation test ([64ac45a](https://github.com/ignaciojulio/Stellar-forge/commit/64ac45ae4179ede5aa0fce9533ffaae640ef2084)) -* resolve build failure blocking strict mode verification ([e3370f5](https://github.com/ignaciojulio/Stellar-forge/commit/e3370f50dec6af5a2780d35d7e11462ecf0c3145)) -* resolve Horizon URL from active network config in useTransactionHistory ([2c25a2d](https://github.com/ignaciojulio/Stellar-forge/commit/2c25a2d2d3b43a72c5453e84f2e2707b4d443696)), closes [#837](https://github.com/ignaciojulio/Stellar-forge/issues/837) -* restore ESLint v9 flat config ([a85d008](https://github.com/ignaciojulio/Stellar-forge/commit/a85d008e18a7f925eff1fd5a7361e624754f28cf)) -* **routing:** fix deep-link for /token/:address and add e2e tests ([1eb308a](https://github.com/ignaciojulio/Stellar-forge/commit/1eb308ab9014c595c30aa3868e9d3e4b87278470)) -* **security:** stop shipping Pinata credentials in the frontend bundle ([#921](https://github.com/ignaciojulio/Stellar-forge/issues/921)) ([2a23cad](https://github.com/ignaciojulio/Stellar-forge/commit/2a23cad10304a6b822720ec0ac4cfe5eb19d3a09)) -* **security:** validate uploaded image content, not client-declared M… ([#1055](https://github.com/ignaciojulio/Stellar-forge/issues/1055)) ([ab1f253](https://github.com/ignaciojulio/Stellar-forge/commit/ab1f25398d2c0a1c2a1a6418364423e5a0dfe577)), closes [#1002](https://github.com/ignaciojulio/Stellar-forge/issues/1002) [#1002](https://github.com/ignaciojulio/Stellar-forge/issues/1002) [#1056](https://github.com/ignaciojulio/Stellar-forge/issues/1056) [#1057](https://github.com/ignaciojulio/Stellar-forge/issues/1057) -* **specs:** resolve spec stubs and enforce kiro spec documentation ([#1117](https://github.com/ignaciojulio/Stellar-forge/issues/1117)) ([#1120](https://github.com/ignaciojulio/Stellar-forge/issues/1120)) ([0875cd2](https://github.com/ignaciojulio/Stellar-forge/commit/0875cd23e96ae0bb87a7d897418349aaa04b18d8)), closes [#1099](https://github.com/ignaciojulio/Stellar-forge/issues/1099) [#1107](https://github.com/ignaciojulio/Stellar-forge/issues/1107) [#1108](https://github.com/ignaciojulio/Stellar-forge/issues/1108) [#1113](https://github.com/ignaciojulio/Stellar-forge/issues/1113) [#1118](https://github.com/ignaciojulio/Stellar-forge/issues/1118) -* stop E2E app crash on unknown network and repair Freighter mock ([232afee](https://github.com/ignaciojulio/Stellar-forge/commit/232afee01997300d0fb64ebbe5101d9c11c520fb)) -* **storybook:** finish the Storybook 10 migration ([a66a453](https://github.com/ignaciojulio/Stellar-forge/commit/a66a453846c86dd2ee83fcb347380b26af4c66ef)), closes [#893](https://github.com/ignaciojulio/Stellar-forge/issues/893) -* **token-factory:** bound fee-split recipient count to prevent resource-exhaustion griefing ([#1027](https://github.com/ignaciojulio/Stellar-forge/issues/1027)) ([becd28f](https://github.com/ignaciojulio/Stellar-forge/commit/becd28f8647eef2fa7e62a9d42b9626413c00216)) -* **token-factory:** enforce strict clippy linting for contract code ([686b143](https://github.com/ignaciojulio/Stellar-forge/commit/686b143cec68646bffeb75790ac317a450742f1f)) -* **token-factory:** extend reentrancy guard to all state-mutating entrypoints ([#972](https://github.com/ignaciojulio/Stellar-forge/issues/972)) ([45a1a9c](https://github.com/ignaciojulio/Stellar-forge/commit/45a1a9c1f077d7dbb4e6989ce6ccf42195e88fce)) -* **token-factory:** reject negative base_fee and metadata_fee ([#973](https://github.com/ignaciojulio/Stellar-forge/issues/973)) ([e3cdd5e](https://github.com/ignaciojulio/Stellar-forge/commit/e3cdd5eb5de4962381800beaa58853b45ee4b46d)) -* **token-factory:** store token_wasm_hash in FactoryState ([7de1635](https://github.com/ignaciojulio/Stellar-forge/commit/7de1635b752553f7166f4e6838620a4dd8d540cc)), closes [#543](https://github.com/ignaciojulio/Stellar-forge/issues/543) -* **ui:** sanitize and validate token name/symbol inputs ([1e4e2e7](https://github.com/ignaciojulio/Stellar-forge/commit/1e4e2e74f4f0dec3fa06cd44bc4892e76dd421d7)) -* upgrade soroban-sdk to 25.x and fix wasm build ([1e098e1](https://github.com/ignaciojulio/Stellar-forge/commit/1e098e149830f6a10e319bd4ac26ef6db8c1c13a)) -* Use correct validation function name in MetadataUploadForm ([b8802cf](https://github.com/ignaciojulio/Stellar-forge/commit/b8802cfd55f2f9f80e2ec76387c9d91b14bce9e5)) -* use dedicated fee_token for all fee transfers in factory contract ([14db340](https://github.com/ignaciojulio/Stellar-forge/commit/14db340019273fbbd6538c240d765aba96906ec5)) -* use formatXLM and stroopsToXLM in FeeDisplay and add conversion test ([65b5d94](https://github.com/ignaciojulio/Stellar-forge/commit/65b5d944ea82d68e68dd816830751533bf58eca2)) -* validate hexToBytes input is exactly 64 hex chars ([4165f9f](https://github.com/ignaciojulio/Stellar-forge/commit/4165f9f3a9d7285fe3ae50c5784f257c73d77716)), closes [#836](https://github.com/ignaciojulio/Stellar-forge/issues/836) -* validate token supply before minting to prevent u128 overflow ([#959](https://github.com/ignaciojulio/Stellar-forge/issues/959)) ([d4027c8](https://github.com/ignaciojulio/Stellar-forge/commit/d4027c81e69c2d2434374a41e8d2bd514a647c26)), closes [#909](https://github.com/ignaciojulio/Stellar-forge/issues/909) -* **validation:** use StrKey checksum validation for Stellar addresses ([c55f0f4](https://github.com/ignaciojulio/Stellar-forge/commit/c55f0f49232a10494906398930488a8eb7e7f9bc)) -* **wallet:** clear all state and token cache on disconnect ([a2b1ed3](https://github.com/ignaciojulio/Stellar-forge/commit/a2b1ed36c3413c37eca259e389307a2f6f06f556)) - +- [#741](https://github.com/ignaciojulio/Stellar-forge/issues/741) AdminPanel restricted to admin address only ([7b2b8c2](https://github.com/ignaciojulio/Stellar-forge/commit/7b2b8c23d40955b39ea300acea24cfeef851d32d)) +- **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1036](https://github.com/ignaciojulio/Stellar-forge/issues/1036)) ([e3174cb](https://github.com/ignaciojulio/Stellar-forge/commit/e3174cb0bde98950c3bf7be8b97beb16a8cd8113)), closes [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) +- **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1037](https://github.com/ignaciojulio/Stellar-forge/issues/1037)) ([116d025](https://github.com/ignaciojulio/Stellar-forge/commit/116d0258ba1a58cfb22f5a12de9107b00e0323d5)), closes [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) [#1024](https://github.com/ignaciojulio/Stellar-forge/issues/1024) [#1023](https://github.com/ignaciojulio/Stellar-forge/issues/1023) +- **#854:** format useTransactionHistory.ts to match project Prettier style (remove semicolons) ([8e7b12b](https://github.com/ignaciojulio/Stellar-forge/commit/8e7b12b757780a3570ec5b425ba61bcf4a23d6b1)), closes [#854](https://github.com/ignaciojulio/Stellar-forge/issues/854) +- **#855:** eliminate CSP duplication by generating index.html meta tag from policy.ts ([1dc325a](https://github.com/ignaciojulio/Stellar-forge/commit/1dc325a503f0f41eb78e5220e1252b4afcb5ee13)), closes [#855](https://github.com/ignaciojulio/Stellar-forge/issues/855) +- **#932:** consolidate useTransactionPolling into useTransaction.ts ([#956](https://github.com/ignaciojulio/Stellar-forge/issues/956)) ([28a84b6](https://github.com/ignaciojulio/Stellar-forge/commit/28a84b67df80e8f6c155e97da6f54704a36113cb)), closes [#932](https://github.com/ignaciojulio/Stellar-forge/issues/932) [#932](https://github.com/ignaciojulio/Stellar-forge/issues/932) +- **#944:** add txHash, network, contractId Sentry tagging on transaction failures ([#952](https://github.com/ignaciojulio/Stellar-forge/issues/952)) ([9c213d0](https://github.com/ignaciojulio/Stellar-forge/commit/9c213d09b089f5704d2748ccc7e3aa2b4fc18a15)), closes [#944](https://github.com/ignaciojulio/Stellar-forge/issues/944) [#944](https://github.com/ignaciojulio/Stellar-forge/issues/944) +- **#945:** document batch resource limits and add frontend size cap ([#953](https://github.com/ignaciojulio/Stellar-forge/issues/953)) ([8555f65](https://github.com/ignaciojulio/Stellar-forge/commit/8555f65acc16ff60cd3108eb533d836ca7fcd0f2)), closes [#945](https://github.com/ignaciojulio/Stellar-forge/issues/945) [#945](https://github.com/ignaciojulio/Stellar-forge/issues/945) +- **#947:** add incident response runbook and break-glass recovery docs ([#954](https://github.com/ignaciojulio/Stellar-forge/issues/954)) ([0546342](https://github.com/ignaciojulio/Stellar-forge/commit/054634208dd995ce8daacbd83199c6c8e3547c2a)), closes [#947](https://github.com/ignaciojulio/Stellar-forge/issues/947) [#9](https://github.com/ignaciojulio/Stellar-forge/issues/9) [#947](https://github.com/ignaciojulio/Stellar-forge/issues/947) +- accept decimals=0 in validateTokenParams ([56cb8d9](https://github.com/ignaciojulio/Stellar-forge/commit/56cb8d961c2d5e421f5391b6d31587ad52013d4b)) +- add bounds validation to token metadata type guard (CWE-1236) ([#964](https://github.com/ignaciojulio/Stellar-forge/issues/964)) ([ab4cb5c](https://github.com/ignaciojulio/Stellar-forge/commit/ab4cb5c31ea6ded2673ee8d4dc61d11f2469d5a7)) +- add BurnAmountExceedsBalance check in burn function ([1113068](https://github.com/ignaciojulio/Stellar-forge/commit/1113068ceb02e464c40066021ca24279dc4753ab)) +- add CI drift check for contract ABI documentation - Closes [#946](https://github.com/ignaciojulio/Stellar-forge/issues/946) ([#949](https://github.com/ignaciojulio/Stellar-forge/issues/949)) ([8e67454](https://github.com/ignaciojulio/Stellar-forge/commit/8e67454a4a4d41c8fe1232eb0d2faebce79f9c6d)) +- add env var validation and misconfiguration screen ([f66f1d5](https://github.com/ignaciojulio/Stellar-forge/commit/f66f1d5c144e9e96ddb451e4feeffca41e950b3d)) +- add esbuild as a direct devDependency for Storybook CI build ([512b11e](https://github.com/ignaciojulio/Stellar-forge/commit/512b11e8cad65979e4fbbdac073ddb8dc5ba1fa8)) +- add formula-injection guard to CSV export (CWE-1236) ([#963](https://github.com/ignaciojulio/Stellar-forge/issues/963)) ([bff7012](https://github.com/ignaciojulio/Stellar-forge/commit/bff70125f81172ece961c8c4f9f2a215e6f746ce)) +- add missing build step to E2E job, fix sitemap script crash ([535955c](https://github.com/ignaciojulio/Stellar-forge/commit/535955c34bbd6b3877fde7f5a29b42288352cdcc)) +- add missing imports for mobile responsive components ([0b89740](https://github.com/ignaciojulio/Stellar-forge/commit/0b89740d64d35bfacddd14b8c6b5a7c4933a4c7b)) +- add standalone network support and fix E2E test mocks ([a78f8de](https://github.com/ignaciojulio/Stellar-forge/commit/a78f8deef5c21e74f3b391726a60636692a242c3)) +- align adm_upd topic and add CI drift detection ([#1032](https://github.com/ignaciojulio/Stellar-forge/issues/1032)) ([872baa9](https://github.com/ignaciojulio/Stellar-forge/commit/872baa9047675607156a731e1c9de78d4e9843fb)) +- align frontend token validation with contract (name ≤ 32 UTF-8 bytes, remove ASCII-only restriction) ([#1125](https://github.com/ignaciojulio/Stellar-forge/issues/1125)) ([cefa9b9](https://github.com/ignaciojulio/Stellar-forge/commit/cefa9b9c13bbc7f2b5a770e5376369c4875c3833)) +- **analytics:** add opt-out tests, CI bypass check, and compliance ADR ([#965](https://github.com/ignaciojulio/Stellar-forge/issues/965)) ([180f672](https://github.com/ignaciojulio/Stellar-forge/commit/180f6725d2f82fa5a068687e428886e85179edd3)), closes [#948](https://github.com/ignaciojulio/Stellar-forge/issues/948) +- **api:** add rate limiting to auth challenge endpoints ([#1144](https://github.com/ignaciojulio/Stellar-forge/issues/1144)) ([600e8a0](https://github.com/ignaciojulio/Stellar-forge/commit/600e8a057f98129ad93a520030c3224682da0400)), closes [#1101](https://github.com/ignaciojulio/Stellar-forge/issues/1101) +- **api:** remove clientIp() dead code with inverted XFF parsing (audit [#26](https://github.com/ignaciojulio/Stellar-forge/issues/26)) ([#1129](https://github.com/ignaciojulio/Stellar-forge/issues/1129)) ([fa1a888](https://github.com/ignaciojulio/Stellar-forge/commit/fa1a888c99133d2fafab52f3e79444d1ac188766)), closes [#1101](https://github.com/ignaciojulio/Stellar-forge/issues/1101) +- **api:** sanitize lastError in health/indexer to avoid leaking internal error details ([#1143](https://github.com/ignaciojulio/Stellar-forge/issues/1143)) ([c51d179](https://github.com/ignaciojulio/Stellar-forge/commit/c51d179b782507f167150b719309715fcf6225d9)), closes [#1103](https://github.com/ignaciojulio/Stellar-forge/issues/1103) +- **api:** store wallet-auth challenges in Vercel KV (Closes [#1091](https://github.com/ignaciojulio/Stellar-forge/issues/1091)) ([#1132](https://github.com/ignaciojulio/Stellar-forge/issues/1132)) ([62941bb](https://github.com/ignaciojulio/Stellar-forge/commit/62941bb0131970c10fc56f5fcf19135eefe8de3f)) +- audit follow-ups — restore tx polling backoff, fix wasm target, drop orphan form ([05409eb](https://github.com/ignaciojulio/Stellar-forge/commit/05409eb55f4e3ff2797fce06d631fc94553a0239)), closes [#852](https://github.com/ignaciojulio/Stellar-forge/issues/852) [#732](https://github.com/ignaciojulio/Stellar-forge/issues/732) [813/#814](https://github.com/ignaciojulio/Stellar-forge/issues/814) +- **build:** build the contract for wasm32v1-none everywhere ([#940](https://github.com/ignaciojulio/Stellar-forge/issues/940)) ([0aa6df3](https://github.com/ignaciojulio/Stellar-forge/commit/0aa6df38bc25e5bf1941a7dbbafd12616a108505)) +- **ci:** remove continue-on-error from fuzz steps, add PR smoke job ([#937](https://github.com/ignaciojulio/Stellar-forge/issues/937)) ([#966](https://github.com/ignaciojulio/Stellar-forge/issues/966)) ([000458f](https://github.com/ignaciojulio/Stellar-forge/commit/000458f8ffde77f136476ea37f2758169f212e07)) +- clear cargo clippy -D warnings findings in token-factory ([2a27a8f](https://github.com/ignaciojulio/Stellar-forge/commit/2a27a8fff3e0b78b5173696166315c1470211a09)) +- complete contract test suite with all error variants covered ([5f8320d](https://github.com/ignaciojulio/Stellar-forge/commit/5f8320d7b14d3a93339ed3f82779d4763a0717b7)) +- **contract:** close open-proxy hole in burn ([#1021](https://github.com/ignaciojulio/Stellar-forge/issues/1021)) ([#1059](https://github.com/ignaciojulio/Stellar-forge/issues/1059)) ([895a621](https://github.com/ignaciojulio/Stellar-forge/commit/895a6218340f8540b8f961ddf47551c96f1c1dbc)) +- **contract:** front-load batch validation and document Soroban transaction atomicity ([#915](https://github.com/ignaciojulio/Stellar-forge/issues/915)) ([#974](https://github.com/ignaciojulio/Stellar-forge/issues/974)) ([b60868f](https://github.com/ignaciojulio/Stellar-forge/commit/b60868f0363e8e6c1c89927cfee42fecef7af34a)) +- **contracts:** add crash-to-regression-test process with fuzz corpus infrastructure ([#951](https://github.com/ignaciojulio/Stellar-forge/issues/951)) ([9428b7d](https://github.com/ignaciojulio/Stellar-forge/commit/9428b7d209366e9ba62ef72359c902cf9beb79b3)), closes [#938](https://github.com/ignaciojulio/Stellar-forge/issues/938) +- **contracts:** add distribute_fee test coverage at realistic split sizes ([#918](https://github.com/ignaciojulio/Stellar-forge/issues/918)) ([#1025](https://github.com/ignaciojulio/Stellar-forge/issues/1025)) ([f9ec953](https://github.com/ignaciojulio/Stellar-forge/commit/f9ec95316a5ee9968094f12947f7a088cd2b24d1)), closes [#919](https://github.com/ignaciojulio/Stellar-forge/issues/919) +- **contracts:** add integer overflow protection in fee arithmetic ([18622f1](https://github.com/ignaciojulio/Stellar-forge/commit/18622f1777201ba92c4db2ef60928faa4c053de3)), closes [#513](https://github.com/ignaciojulio/Stellar-forge/issues/513) +- **contracts:** charge exactly the required fee, not fee_payment ([#1035](https://github.com/ignaciojulio/Stellar-forge/issues/1035)) ([8654767](https://github.com/ignaciojulio/Stellar-forge/commit/86547670d6b45bf9a967ea59e26813b2670de6b5)), closes [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) [#1008](https://github.com/ignaciojulio/Stellar-forge/issues/1008) [#1008](https://github.com/ignaciojulio/Stellar-forge/issues/1008) +- **contracts:** close remaining FWC26 audit issues ([787dc22](https://github.com/ignaciojulio/Stellar-forge/commit/787dc22d4272d0258856b6a31967c164dcefddda)), closes [909-#948](https://github.com/909-/issues/948) [#1022](https://github.com/ignaciojulio/Stellar-forge/issues/1022) [#910](https://github.com/ignaciojulio/Stellar-forge/issues/910) [#913](https://github.com/ignaciojulio/Stellar-forge/issues/913) [#916](https://github.com/ignaciojulio/Stellar-forge/issues/916) [#943](https://github.com/ignaciojulio/Stellar-forge/issues/943) +- **contracts:** enforce MAX_BATCH_SIZE cap in create_tokens_batch (Closes [#1100](https://github.com/ignaciojulio/Stellar-forge/issues/1100)) ([#1135](https://github.com/ignaciojulio/Stellar-forge/issues/1135)) ([2ba33e5](https://github.com/ignaciojulio/Stellar-forge/commit/2ba33e5e5516b2e3e66388ebd3dcb4568a3b5a14)) +- **contracts:** fuzz the real burn entrypoint, not a reimplementation ([#1098](https://github.com/ignaciojulio/Stellar-forge/issues/1098)) ([#1137](https://github.com/ignaciojulio/Stellar-forge/issues/1137)) ([be8a342](https://github.com/ignaciojulio/Stellar-forge/commit/be8a3424d514423f9946635ff899440911bd3377)) +- **contracts:** make token-factory initialize atomic with deployment ([#1029](https://github.com/ignaciojulio/Stellar-forge/issues/1029)) ([3e12de2](https://github.com/ignaciojulio/Stellar-forge/commit/3e12de21ff69c7998ff0ad591bc8f066009e364f)), closes [#1005](https://github.com/ignaciojulio/Stellar-forge/issues/1005) +- **contracts:** move per-token bookkeeping to persistent storage ([#1034](https://github.com/ignaciojulio/Stellar-forge/issues/1034)) ([51c52bd](https://github.com/ignaciojulio/Stellar-forge/commit/51c52bd1bcb07eeda1744cd99f82a2816db6aa27)), closes [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) [#1007](https://github.com/ignaciojulio/Stellar-forge/issues/1007) +- **contracts:** prove multi-step migrate pattern with synthetic v2 tests ([#919](https://github.com/ignaciojulio/Stellar-forge/issues/919)) ([#1026](https://github.com/ignaciojulio/Stellar-forge/issues/1026)) ([f9ef384](https://github.com/ignaciojulio/Stellar-forge/commit/f9ef3849f30d7af08473cd66268c0692def6da91)), closes [#918](https://github.com/ignaciojulio/Stellar-forge/issues/918) [#918](https://github.com/ignaciojulio/Stellar-forge/issues/918) +- **contracts:** repair broken merge artifacts on main ([#1041](https://github.com/ignaciojulio/Stellar-forge/issues/1041)) ([6524e58](https://github.com/ignaciojulio/Stellar-forge/commit/6524e58d86b00235622cb07e89d30a756df69f8e)), closes [1034/#1035](https://github.com/ignaciojulio/Stellar-forge/issues/1035) [#1033](https://github.com/ignaciojulio/Stellar-forge/issues/1033) [#1034](https://github.com/ignaciojulio/Stellar-forge/issues/1034) [#1025](https://github.com/ignaciojulio/Stellar-forge/issues/1025) +- **contracts:** seed max-supply counter with initial_supply ([#1006](https://github.com/ignaciojulio/Stellar-forge/issues/1006)) ([#1031](https://github.com/ignaciojulio/Stellar-forge/issues/1031)) ([4a3e90d](https://github.com/ignaciojulio/Stellar-forge/commit/4a3e90de113d45a28f67c765c4a7c07af38c7e44)) +- correct useLocalStorage syntax error and variable reference ([232fc52](https://github.com/ignaciojulio/Stellar-forge/commit/232fc520e4df8a4d1345e67e05084ae32252fe5e)) +- dedupe token-validation rules in validation.ts ([d3012c2](https://github.com/ignaciojulio/Stellar-forge/commit/d3012c2c310f31135a463f13482af36ec9b1dc46)), closes [#845](https://github.com/ignaciojulio/Stellar-forge/issues/845) +- **deps:** add Dependabot fuzz coverage and auto-merge policy ([#985](https://github.com/ignaciojulio/Stellar-forge/issues/985)) ([2247b9f](https://github.com/ignaciojulio/Stellar-forge/commit/2247b9f0cb3343708d5eebb461280d7e558a5b38)), closes [#941](https://github.com/ignaciojulio/Stellar-forge/issues/941) +- downgrade vite to v6 for Storybook compatibility ([c2f071b](https://github.com/ignaciojulio/Stellar-forge/commit/c2f071bb75ced96669d27f11cec13e11d9c83358)) +- **e2e:** add token-list-container class and show 6 trailing address chars ([9fcfff3](https://github.com/ignaciojulio/Stellar-forge/commit/9fcfff3398df79dd9ad987ff4ad51d15409f78b6)) +- **e2e:** prevent watcher auto-connect by not responding to REQUEST_NETWORK_DETAILS ([9649702](https://github.com/ignaciojulio/Stellar-forge/commit/9649702d0793d0e489bb9eb2caba0217f3ab99dc)) +- exclude fuzz crate from workspace to prevent wasm32 compilation errors ([b3f09f2](https://github.com/ignaciojulio/Stellar-forge/commit/b3f09f208486b314a10fd2f8061b90631fa5df3a)) +- expand .gitignore to prevent accidental commits of local artifacts ([1da56fe](https://github.com/ignaciojulio/Stellar-forge/commit/1da56fe00394ccbbff2a86d0de8fa7cf24356924)), closes [#835](https://github.com/ignaciojulio/Stellar-forge/issues/835) +- **explorer:** snapshot tokenCount once per session to prevent pagination drift ([#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126)) ([a27f77b](https://github.com/ignaciojulio/Stellar-forge/commit/a27f77b8dda5b76feced0cf6baeac7a42a84bcf0)) +- **frontend:** clear typecheck errors and prettier drift masked by red CI ([82994b9](https://github.com/ignaciojulio/Stellar-forge/commit/82994b977781c0b616e68b29fa1e1859765b0ac9)) +- **frontend:** close network-mismatch signing window with a fresh pre-sign check ([#961](https://github.com/ignaciojulio/Stellar-forge/issues/961)) ([7619e99](https://github.com/ignaciojulio/Stellar-forge/commit/7619e9960d68ad73f6fb67ee0f4f9d11d6ee6ba6)), closes [#927](https://github.com/ignaciojulio/Stellar-forge/issues/927) +- **frontend:** close unclosed PR wrapper in App.tsx and remove duplicate route entries ([4f9442b](https://github.com/ignaciojulio/Stellar-forge/commit/4f9442bda20864966521c36f1ed4272c52f56dd2)) +- **frontend:** establish transaction reconciliation policy and add phantom-entry guards ([#955](https://github.com/ignaciojulio/Stellar-forge/issues/955)) ([1372af1](https://github.com/ignaciojulio/Stellar-forge/commit/1372af165a869a1814ef9b43d22c9e9f507190f2)), closes [#933](https://github.com/ignaciojulio/Stellar-forge/issues/933) +- **frontend:** filter-aware cache key, stable useCallback deps, re-fetch on filter change ([62d2c8c](https://github.com/ignaciojulio/Stellar-forge/commit/62d2c8c3aaba49c1099b30db5e3956747b407b9a)) +- **frontend:** fix Option encoding, map missing topics, add cap field ([fb3ee73](https://github.com/ignaciojulio/Stellar-forge/commit/fb3ee73daa47161d932d9f91585762223afa6a1a)), closes [#1022](https://github.com/ignaciojulio/Stellar-forge/issues/1022) [#917](https://github.com/ignaciojulio/Stellar-forge/issues/917) [#1022](https://github.com/ignaciojulio/Stellar-forge/issues/1022) [#943](https://github.com/ignaciojulio/Stellar-forge/issues/943) +- **frontend:** handle every sendTransaction status explicitly ([#1020](https://github.com/ignaciojulio/Stellar-forge/issues/1020)) ([#1058](https://github.com/ignaciojulio/Stellar-forge/issues/1058)) ([70ebab6](https://github.com/ignaciojulio/Stellar-forge/commit/70ebab62bea7d7dc887e3ce6852a7f436b023083)), closes [#1056](https://github.com/ignaciojulio/Stellar-forge/issues/1056) [#1057](https://github.com/ignaciojulio/Stellar-forge/issues/1057) +- **frontend:** implement the CSV formula-injection guard its tests expected ([59839b6](https://github.com/ignaciojulio/Stellar-forge/commit/59839b603cf7a84d782a740ff455e9bc9748ed62)), closes [#963](https://github.com/ignaciojulio/Stellar-forge/issues/963) +- **frontend:** make token-detail routes public for deep links ([#880](https://github.com/ignaciojulio/Stellar-forge/issues/880)) ([971e14b](https://github.com/ignaciojulio/Stellar-forge/commit/971e14b24097a4f08688b097225728ed22955c6e)) +- **frontend:** only mount OnboardingModal on Help click, not first-visit ([87d3ce4](https://github.com/ignaciojulio/Stellar-forge/commit/87d3ce41a764067f90f0384ce795f6111fdcaeec)) +- **frontend:** paginate factory event fetch instead of silently capping "all tokens" ([#962](https://github.com/ignaciojulio/Stellar-forge/issues/962)) ([b480f56](https://github.com/ignaciojulio/Stellar-forge/commit/b480f56b8f935802aab26d2384efcb3eb3da9080)), closes [#35](https://github.com/ignaciojulio/Stellar-forge/issues/35) +- **frontend:** pay real base_fee, surface FeeDisplay in mint, block writes on network mismatch ([6d5697d](https://github.com/ignaciojulio/Stellar-forge/commit/6d5697d3f661be16c4fefccdb1a71f5b5d35734b)) +- **frontend:** remove exhaustive-deps suppressions, fix dep arrays ([a8fcf34](https://github.com/ignaciojulio/Stellar-forge/commit/a8fcf3463afe36bacf28f5f1f259eb5f8e7ca845)) +- **frontend:** resolve merge fallout — format, getMetadata validation, no-this-alias ([4e0d770](https://github.com/ignaciojulio/Stellar-forge/commit/4e0d77063f0d8b10f23cc9176ea2217bf9337b08)) +- **frontend:** resolve token identity from contract, not events ([#1018](https://github.com/ignaciojulio/Stellar-forge/issues/1018)) ([#1030](https://github.com/ignaciojulio/Stellar-forge/issues/1030)) ([66bcb19](https://github.com/ignaciojulio/Stellar-forge/commit/66bcb1915e5199371a1b49f5b353e0aba0dfd86a)) +- **frontend:** source FeeDisplay fees from useFactoryState, not the singleton ([e388e7a](https://github.com/ignaciojulio/Stellar-forge/commit/e388e7aacaf66708e01aba263121bd9b932895b2)) +- **frontend:** stop passing a decimal XLM string to formatXLM ([d23be61](https://github.com/ignaciojulio/Stellar-forge/commit/d23be616d378af583289ce5544de20673eeb5fda)) +- **frontend:** track Horizon paging_token and pass cursor on load-more ([aa6e15b](https://github.com/ignaciojulio/Stellar-forge/commit/aa6e15b235bda5842fed1e8aa5848a2e06b04959)) +- **frontend:** unify transaction poll backoff into shared utility ([#960](https://github.com/ignaciojulio/Stellar-forge/issues/960)) ([2ad85fc](https://github.com/ignaciojulio/Stellar-forge/commit/2ad85fc7f43c40a66746519eccaf89cb5147e53c)) +- **frontend:** wire orphaned features, fix standalone network, add typecheck gate ([c14d1b1](https://github.com/ignaciojulio/Stellar-forge/commit/c14d1b108ef210ede1d007f231cd4797f844fe26)) +- **infra:** consolidate vercel.json security headers (Closes [#1104](https://github.com/ignaciojulio/Stellar-forge/issues/1104)) ([#1134](https://github.com/ignaciojulio/Stellar-forge/issues/1134)) ([fc64bea](https://github.com/ignaciojulio/Stellar-forge/commit/fc64bea1d5185c43fe289214857246bfe014e51c)) +- **infra:** schedule the indexer cron in vercel.json (Closes [#1090](https://github.com/ignaciojulio/Stellar-forge/issues/1090)) ([#1130](https://github.com/ignaciojulio/Stellar-forge/issues/1130)) ([288d5f3](https://github.com/ignaciojulio/Stellar-forge/commit/288d5f3b1208405fd08e12342fef2ae58cf25a7b)), closes [#1123](https://github.com/ignaciojulio/Stellar-forge/issues/1123) [#1124](https://github.com/ignaciojulio/Stellar-forge/issues/1124) [#1125](https://github.com/ignaciojulio/Stellar-forge/issues/1125) [#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126) [#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126) [#1126](https://github.com/ignaciojulio/Stellar-forge/issues/1126) [#1121](https://github.com/ignaciojulio/Stellar-forge/issues/1121) [#1121](https://github.com/ignaciojulio/Stellar-forge/issues/1121) +- **ipfs:** retry image upload on transient Pinata errors ([26a2005](https://github.com/ignaciojulio/Stellar-forge/commit/26a2005ebfbe5c27c7f132c3f0a031d5c750ac30)), closes [#743](https://github.com/ignaciojulio/Stellar-forge/issues/743) +- **ipfs:** validate getMetadata response shape before returning ([7183346](https://github.com/ignaciojulio/Stellar-forge/commit/71833467e8e0aa7c8a770d2905056227e721378c)), closes [#849](https://github.com/ignaciojulio/Stellar-forge/issues/849) +- isolate per-recipient fee-split transfer failures from aborting the call ([#1136](https://github.com/ignaciojulio/Stellar-forge/issues/1136)) ([6e68f0d](https://github.com/ignaciojulio/Stellar-forge/commit/6e68f0d78f1272fa6a31cc6d8cb54859dc9fb83b)) +- make all 202 tests pass ([1043432](https://github.com/ignaciojulio/Stellar-forge/commit/1043432dcdf6307385661d7261fd8f73bcae6923)) +- pin esbuild/globals devDeps and apply npm audit fixes ([6ccd8c3](https://github.com/ignaciojulio/Stellar-forge/commit/6ccd8c3418b8617052bd8c290231cabad9d82119)) +- provide VITE_TOKEN_WASM_HASH in E2E CI job ([64c1a5b](https://github.com/ignaciojulio/Stellar-forge/commit/64c1a5b24f90f4685b1690b8653e620768924240)) +- real bugs surfaced while restoring lint/test coverage ([8434f56](https://github.com/ignaciojulio/Stellar-forge/commit/8434f5688c3f8877513c5931eef26bf93b85091f)) +- reclaim orphaned IPFS pins on failed set_metadata (Closes [#1096](https://github.com/ignaciojulio/Stellar-forge/issues/1096)) ([#1146](https://github.com/ignaciojulio/Stellar-forge/issues/1146)) ([d845880](https://github.com/ignaciojulio/Stellar-forge/commit/d84588094a620097ffcb3d66135201ffedc70ad8)) +- redesign fee transfer and token deployment per issue spec ([e7b8c9e](https://github.com/ignaciojulio/Stellar-forge/commit/e7b8c9e7f0a77cb618b39afa0b91ea6ac87c5b21)) +- refactor build system, fix contract errors, fix dark mode toggle ([85751f8](https://github.com/ignaciojulio/Stellar-forge/commit/85751f85239640acbae8197feccb14ff63724c16)) +- relabel TokenDetail Admin field to 'Deployed by' (Closes [#1109](https://github.com/ignaciojulio/Stellar-forge/issues/1109)) ([#1119](https://github.com/ignaciojulio/Stellar-forge/issues/1119)) ([5d5df07](https://github.com/ignaciojulio/Stellar-forge/commit/5d5df075612a6e510448e17087c281d987a36478)) +- **release:** add @actions/io to satisfy @actions/exec's undeclared import ([cd21fdc](https://github.com/ignaciojulio/Stellar-forge/commit/cd21fdc70110759165e95d85803d48f15dd7225f)) +- **release:** disable husky hooks in the release workflow ([5429060](https://github.com/ignaciojulio/Stellar-forge/commit/5429060a58cf30265f835f3954a420de043452df)) +- remove 'unsafe-inline' from CSP style-src (Closes [#1105](https://github.com/ignaciojulio/Stellar-forge/issues/1105)) ([#1123](https://github.com/ignaciojulio/Stellar-forge/issues/1123)) ([838129c](https://github.com/ignaciojulio/Stellar-forge/commit/838129ccc63f862350ac86ee1efcc1ba2ae4a163)) +- repair local Stellar network startup in E2E CI job ([5aa9026](https://github.com/ignaciojulio/Stellar-forge/commit/5aa90265077404369cfe81c6a96eb94017075893)) +- replace console.error with logger in CreateToken, TokenForm, MetadataUploadForm ([24805af](https://github.com/ignaciojulio/Stellar-forge/commit/24805af56b93e60392a4817ba8708c29960dd043)), closes [#848](https://github.com/ignaciojulio/Stellar-forge/issues/848) +- replace invalid checksum address in validation test ([64ac45a](https://github.com/ignaciojulio/Stellar-forge/commit/64ac45ae4179ede5aa0fce9533ffaae640ef2084)) +- resolve build failure blocking strict mode verification ([e3370f5](https://github.com/ignaciojulio/Stellar-forge/commit/e3370f50dec6af5a2780d35d7e11462ecf0c3145)) +- resolve Horizon URL from active network config in useTransactionHistory ([2c25a2d](https://github.com/ignaciojulio/Stellar-forge/commit/2c25a2d2d3b43a72c5453e84f2e2707b4d443696)), closes [#837](https://github.com/ignaciojulio/Stellar-forge/issues/837) +- restore ESLint v9 flat config ([a85d008](https://github.com/ignaciojulio/Stellar-forge/commit/a85d008e18a7f925eff1fd5a7361e624754f28cf)) +- **routing:** fix deep-link for /token/:address and add e2e tests ([1eb308a](https://github.com/ignaciojulio/Stellar-forge/commit/1eb308ab9014c595c30aa3868e9d3e4b87278470)) +- **security:** stop shipping Pinata credentials in the frontend bundle ([#921](https://github.com/ignaciojulio/Stellar-forge/issues/921)) ([2a23cad](https://github.com/ignaciojulio/Stellar-forge/commit/2a23cad10304a6b822720ec0ac4cfe5eb19d3a09)) +- **security:** validate uploaded image content, not client-declared M… ([#1055](https://github.com/ignaciojulio/Stellar-forge/issues/1055)) ([ab1f253](https://github.com/ignaciojulio/Stellar-forge/commit/ab1f25398d2c0a1c2a1a6418364423e5a0dfe577)), closes [#1002](https://github.com/ignaciojulio/Stellar-forge/issues/1002) [#1002](https://github.com/ignaciojulio/Stellar-forge/issues/1002) [#1056](https://github.com/ignaciojulio/Stellar-forge/issues/1056) [#1057](https://github.com/ignaciojulio/Stellar-forge/issues/1057) +- **specs:** resolve spec stubs and enforce kiro spec documentation ([#1117](https://github.com/ignaciojulio/Stellar-forge/issues/1117)) ([#1120](https://github.com/ignaciojulio/Stellar-forge/issues/1120)) ([0875cd2](https://github.com/ignaciojulio/Stellar-forge/commit/0875cd23e96ae0bb87a7d897418349aaa04b18d8)), closes [#1099](https://github.com/ignaciojulio/Stellar-forge/issues/1099) [#1107](https://github.com/ignaciojulio/Stellar-forge/issues/1107) [#1108](https://github.com/ignaciojulio/Stellar-forge/issues/1108) [#1113](https://github.com/ignaciojulio/Stellar-forge/issues/1113) [#1118](https://github.com/ignaciojulio/Stellar-forge/issues/1118) +- stop E2E app crash on unknown network and repair Freighter mock ([232afee](https://github.com/ignaciojulio/Stellar-forge/commit/232afee01997300d0fb64ebbe5101d9c11c520fb)) +- **storybook:** finish the Storybook 10 migration ([a66a453](https://github.com/ignaciojulio/Stellar-forge/commit/a66a453846c86dd2ee83fcb347380b26af4c66ef)), closes [#893](https://github.com/ignaciojulio/Stellar-forge/issues/893) +- **token-factory:** bound fee-split recipient count to prevent resource-exhaustion griefing ([#1027](https://github.com/ignaciojulio/Stellar-forge/issues/1027)) ([becd28f](https://github.com/ignaciojulio/Stellar-forge/commit/becd28f8647eef2fa7e62a9d42b9626413c00216)) +- **token-factory:** enforce strict clippy linting for contract code ([686b143](https://github.com/ignaciojulio/Stellar-forge/commit/686b143cec68646bffeb75790ac317a450742f1f)) +- **token-factory:** extend reentrancy guard to all state-mutating entrypoints ([#972](https://github.com/ignaciojulio/Stellar-forge/issues/972)) ([45a1a9c](https://github.com/ignaciojulio/Stellar-forge/commit/45a1a9c1f077d7dbb4e6989ce6ccf42195e88fce)) +- **token-factory:** reject negative base_fee and metadata_fee ([#973](https://github.com/ignaciojulio/Stellar-forge/issues/973)) ([e3cdd5e](https://github.com/ignaciojulio/Stellar-forge/commit/e3cdd5eb5de4962381800beaa58853b45ee4b46d)) +- **token-factory:** store token_wasm_hash in FactoryState ([7de1635](https://github.com/ignaciojulio/Stellar-forge/commit/7de1635b752553f7166f4e6838620a4dd8d540cc)), closes [#543](https://github.com/ignaciojulio/Stellar-forge/issues/543) +- **ui:** sanitize and validate token name/symbol inputs ([1e4e2e7](https://github.com/ignaciojulio/Stellar-forge/commit/1e4e2e74f4f0dec3fa06cd44bc4892e76dd421d7)) +- upgrade soroban-sdk to 25.x and fix wasm build ([1e098e1](https://github.com/ignaciojulio/Stellar-forge/commit/1e098e149830f6a10e319bd4ac26ef6db8c1c13a)) +- Use correct validation function name in MetadataUploadForm ([b8802cf](https://github.com/ignaciojulio/Stellar-forge/commit/b8802cfd55f2f9f80e2ec76387c9d91b14bce9e5)) +- use dedicated fee_token for all fee transfers in factory contract ([14db340](https://github.com/ignaciojulio/Stellar-forge/commit/14db340019273fbbd6538c240d765aba96906ec5)) +- use formatXLM and stroopsToXLM in FeeDisplay and add conversion test ([65b5d94](https://github.com/ignaciojulio/Stellar-forge/commit/65b5d944ea82d68e68dd816830751533bf58eca2)) +- validate hexToBytes input is exactly 64 hex chars ([4165f9f](https://github.com/ignaciojulio/Stellar-forge/commit/4165f9f3a9d7285fe3ae50c5784f257c73d77716)), closes [#836](https://github.com/ignaciojulio/Stellar-forge/issues/836) +- validate token supply before minting to prevent u128 overflow ([#959](https://github.com/ignaciojulio/Stellar-forge/issues/959)) ([d4027c8](https://github.com/ignaciojulio/Stellar-forge/commit/d4027c81e69c2d2434374a41e8d2bd514a647c26)), closes [#909](https://github.com/ignaciojulio/Stellar-forge/issues/909) +- **validation:** use StrKey checksum validation for Stellar addresses ([c55f0f4](https://github.com/ignaciojulio/Stellar-forge/commit/c55f0f49232a10494906398930488a8eb7e7f9bc)) +- **wallet:** clear all state and token cache on disconnect ([a2b1ed3](https://github.com/ignaciojulio/Stellar-forge/commit/a2b1ed36c3413c37eca259e389307a2f6f06f556)) ### Features -* **#588:** Build Token Creation Form UI ([b13478c](https://github.com/ignaciojulio/Stellar-forge/commit/b13478ce4ce5f7f5ff75bd629ee82c8e77c6e00b)), closes [#588](https://github.com/ignaciojulio/Stellar-forge/issues/588) -* **#589:** Implement StellarService Token Deployment ([b186936](https://github.com/ignaciojulio/Stellar-forge/commit/b18693646c7a9a6826cae19aef04b6b97fe95e16)), closes [#589](https://github.com/ignaciojulio/Stellar-forge/issues/589) -* **#590:** Implement IPFS Metadata Upload via Pinata ([98e1fc0](https://github.com/ignaciojulio/Stellar-forge/commit/98e1fc05522b123fdfba8949d4f891d09ca36315)), closes [#590](https://github.com/ignaciojulio/Stellar-forge/issues/590) -* **#603:** Create Token Detail Page ([a1aa1ec](https://github.com/ignaciojulio/Stellar-forge/commit/a1aa1ecd6ccad4ec4e2b00a59e706cff4b133c13)), closes [#603](https://github.com/ignaciojulio/Stellar-forge/issues/603) -* **#604:** Add React Router for Navigation ([be195b5](https://github.com/ignaciojulio/Stellar-forge/commit/be195b50249bb8d3cfe632338b279ccbab3078c1)), closes [#604](https://github.com/ignaciojulio/Stellar-forge/issues/604) -* **#606:** Add loading states and skeleton UI ([41111e0](https://github.com/ignaciojulio/Stellar-forge/commit/41111e0675574976efd551268375a5f5aafa094e)), closes [#606](https://github.com/ignaciojulio/Stellar-forge/issues/606) -* **#607:** Add environment variable validation on startup ([5e3ff84](https://github.com/ignaciojulio/Stellar-forge/commit/5e3ff842dee16505f089da8fa8ddf59ff1cbf0aa)), closes [#607](https://github.com/ignaciojulio/Stellar-forge/issues/607) -* **#734:** Add debounced search and creator address filter to TokenExplorer ([12c703b](https://github.com/ignaciojulio/Stellar-forge/commit/12c703bf6f4ef881be1aec3fb7a31659182a05fb)), closes [#734](https://github.com/ignaciojulio/Stellar-forge/issues/734) -* **#fuzz:** add fuzz targets for set_metadata and mint_tokens ([167432d](https://github.com/ignaciojulio/Stellar-forge/commit/167432dc36b3a44d2fa2b3bcd891af976dc06ab6)), closes [#fuzz](https://github.com/ignaciojulio/Stellar-forge/issues/fuzz) -* **a11y:** accessibility audit and fixes ([98eb2f7](https://github.com/ignaciojulio/Stellar-forge/commit/98eb2f7bce43199095257b3f21b29347db71fb7d)) -* add accessibility improvements (a11y) ([259d1b0](https://github.com/ignaciojulio/Stellar-forge/commit/259d1b0ba239906605b10feb7a151deea01bb70b)) -* add AddressDisplay component with copy and explorer link ([2ab3bda](https://github.com/ignaciojulio/Stellar-forge/commit/2ab3bdaa16ba838f6da55e681983df940707cb31)) -* add analytics integration spec and scaffolding ([#522](https://github.com/ignaciojulio/Stellar-forge/issues/522)) ([e4d8902](https://github.com/ignaciojulio/Stellar-forge/commit/e4d89029fe13ea8a94a574bc2028f9090bc51cc0)) -* add CHANGELOG.md and PR template with changelog checklist ([89bb67e](https://github.com/ignaciojulio/Stellar-forge/commit/89bb67ed0b73c25e9a0fad46554b8ee6c35e17cb)) -* add client-side CID verification for metadata integrity ([#1139](https://github.com/ignaciojulio/Stellar-forge/issues/1139)) ([82e9a1b](https://github.com/ignaciojulio/Stellar-forge/commit/82e9a1b72bf1c78efede6522669d40707a5f295c)) -* add client-side routing with react-router-dom (fixes [#471](https://github.com/ignaciojulio/Stellar-forge/issues/471)) ([baee94d](https://github.com/ignaciojulio/Stellar-forge/commit/baee94d5865dea41be3e3a0caa3a70952c8f45b3)) -* add comprehensive error handling system ([62b4348](https://github.com/ignaciojulio/Stellar-forge/commit/62b43485f363fcdd348e518631221dcdedbca452)) -* add ConfirmModal before all on-chain transactions ([3cef134](https://github.com/ignaciojulio/Stellar-forge/commit/3cef134598c07ec70c6c8d7ed84549da9a0c6162)) -* add Content-Security-Policy headers ([ef28578](https://github.com/ignaciojulio/Stellar-forge/commit/ef285786231bd883fab9b5e4f2e369658cb010b4)) -* add contract event history with pagination ([0425f56](https://github.com/ignaciojulio/Stellar-forge/commit/0425f560eb14fe3ab740e9e1726e045d9259772a)) -* add contract event indexing spec ([#612](https://github.com/ignaciojulio/Stellar-forge/issues/612)) ([5952c01](https://github.com/ignaciojulio/Stellar-forge/commit/5952c015de58f01b79a0a3978f7baa09e1ec8c4c)) -* add CopyButton component and integrations [#491](https://github.com/ignaciojulio/Stellar-forge/issues/491) ([6d16970](https://github.com/ignaciojulio/Stellar-forge/commit/6d1697051d31d6876a50008a3d7669f69d5315b6)) -* add dark mode support with localStorage persistence ([24e96e5](https://github.com/ignaciojulio/Stellar-forge/commit/24e96e584e68fdf5177d3631d5172f390ed08465)) -* add dark mode with system preference, localStorage persistence, and toggle button ([5658728](https://github.com/ignaciojulio/Stellar-forge/commit/5658728f0ba9b5825e3f002c10a8a381c4434ced)) -* add decimals validation for create_token (0-18 inclusive) ([f88ec3c](https://github.com/ignaciojulio/Stellar-forge/commit/f88ec3c3e3100c34bb383c6b90a92fcb1fd33cc4)), closes [#515](https://github.com/ignaciojulio/Stellar-forge/issues/515) -* add deploy-contract.sh script for automated contract deployment ([f478eb2](https://github.com/ignaciojulio/Stellar-forge/commit/f478eb2f264a2ad65366be6217dd897ab5ca1e26)) -* add E2E coverage for network mismatch guard across all write forms Closes [#935](https://github.com/ignaciojulio/Stellar-forge/issues/935) ([#970](https://github.com/ignaciojulio/Stellar-forge/issues/970)) ([a644ce6](https://github.com/ignaciojulio/Stellar-forge/commit/a644ce657163e43308840ecb8e4a5582b7046cf7)) -* add env variable validation and configuration guide ([98642d9](https://github.com/ignaciojulio/Stellar-forge/commit/98642d9dd07b242b72fa17f7c71c90749209cf71)), closes [#8](https://github.com/ignaciojulio/Stellar-forge/issues/8) -* add ErrorBoundary component to catch render errors ([d297816](https://github.com/ignaciojulio/Stellar-forge/commit/d29781600265a3afc90e905556a2b1c995f2dd29)) -* add eslint import order rule spec ([ca4bc6b](https://github.com/ignaciojulio/Stellar-forge/commit/ca4bc6bad5f926f67845006654a62d413a8d7446)) -* add export CSV functionality to TransactionHistory ([637dc7c](https://github.com/ignaciojulio/Stellar-forge/commit/637dc7cfdb0c15520196983a6f5a87e0504fe0a1)) -* add fee bump transaction support ([#63](https://github.com/ignaciojulio/Stellar-forge/issues/63)) ([9b2b8ea](https://github.com/ignaciojulio/Stellar-forge/commit/9b2b8ea83cad398c574e53d1b5e50876c58252e7)) -* add FeeDisplay component with module-level cache ([e749987](https://github.com/ignaciojulio/Stellar-forge/commit/e749987653db420fb5261cbe857fb557a697ecd1)) -* add formatTimestamp and timeAgo utilities (#issue) ([02f8f30](https://github.com/ignaciojulio/Stellar-forge/commit/02f8f308f23c64b660d3419496b21085f9f35059)), closes [#issue](https://github.com/ignaciojulio/Stellar-forge/issues/issue) -* add formatTokenAmount and parseTokenAmount utilities ([1041ada](https://github.com/ignaciojulio/Stellar-forge/commit/1041ada734af076be7fd095d40e6c87ab39b58ed)) -* add French (fr) locale i18n support ([4429f89](https://github.com/ignaciojulio/Stellar-forge/commit/4429f898c5906e2f42b38d3b3069af5acf8b07bd)), closes [#740](https://github.com/ignaciojulio/Stellar-forge/issues/740) -* add friendbot banner for testnet ([aece4cb](https://github.com/ignaciojulio/Stellar-forge/commit/aece4cb99d882cf89cd6e87ba8a97312300ead57)) -* add frontend unit tests and fix retry unhandled rejections ([ec4b78b](https://github.com/ignaciojulio/Stellar-forge/commit/ec4b78b50b9ce92b0c37c64e705b0bd81a0f5f10)), closes [#9](https://github.com/ignaciojulio/Stellar-forge/issues/9) -* add frontend unit tests for validation utils ([#609](https://github.com/ignaciojulio/Stellar-forge/issues/609)) ([5ef4995](https://github.com/ignaciojulio/Stellar-forge/commit/5ef4995f2fce86123490a70b7a320a21ef5cdd19)) -* add get_tokens_by_creator view function ([#38](https://github.com/ignaciojulio/Stellar-forge/issues/38)) ([17b7ae0](https://github.com/ignaciojulio/Stellar-forge/commit/17b7ae09f4e8bca9660d61389704a18eab50a42f)) -* add global toast notification system ([ea22272](https://github.com/ignaciojulio/Stellar-forge/commit/ea22272f16cffdd0390b85ceb56a54fd0fbf519e)) -* Add husky + lint-staged pre-commit hooks ([#59](https://github.com/ignaciojulio/Stellar-forge/issues/59)) ([b11c468](https://github.com/ignaciojulio/Stellar-forge/commit/b11c4682e0bf0fbcf4b9885237b135142211c366)) -* add Husky pre-commit and pre-push hooks ([#533](https://github.com/ignaciojulio/Stellar-forge/issues/533)) ([c232169](https://github.com/ignaciojulio/Stellar-forge/commit/c232169967c5bcf58d07aeb4885efeed39444ce0)) -* add i18n foundation with react-i18next ([0f8c270](https://github.com/ignaciojulio/Stellar-forge/commit/0f8c2706990f5b6b6ce9f4c17876efee909929b1)) -* add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/ignaciojulio/Stellar-forge/issues/33)) ([5ba129f](https://github.com/ignaciojulio/Stellar-forge/commit/5ba129f8148add491d6dfd406138a3a3ab3a7f1c)) -* add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/ignaciojulio/Stellar-forge/issues/33)) ([9e76fc4](https://github.com/ignaciojulio/Stellar-forge/commit/9e76fc48a45c3512ffcc7e9c5edffae81dd0fdf6)) -* Add mainnet deployment checklist modal ([#35](https://github.com/ignaciojulio/Stellar-forge/issues/35)) ([d3e8f2d](https://github.com/ignaciojulio/Stellar-forge/commit/d3e8f2dfd04536bc5fede24ca84d1e0d416c8e39)) -* add MetadataAlreadySet guard in set_metadata ([ebbdd65](https://github.com/ignaciojulio/Stellar-forge/commit/ebbdd65360b829419d112b4dc8544c0396502a65)) -* add MintForm component with address validation and mintTokens service ([ac9df39](https://github.com/ignaciojulio/Stellar-forge/commit/ac9df395c2e4b4ad710f86211f0ee626e76238e0)) -* add network switching support ([#680](https://github.com/ignaciojulio/Stellar-forge/issues/680)) ([60e9f3f](https://github.com/ignaciojulio/Stellar-forge/commit/60e9f3fb185c5be0e93d0763c1ada5c6818ec3f3)) -* add OG tags, react-router-dom, clippy CI, and npm ci ([24d091c](https://github.com/ignaciojulio/Stellar-forge/commit/24d091c957c65e2b03eb374edfeb9f62c780d969)), closes [#54](https://github.com/ignaciojulio/Stellar-forge/issues/54) [#56](https://github.com/ignaciojulio/Stellar-forge/issues/56) [#68](https://github.com/ignaciojulio/Stellar-forge/issues/68) [#85](https://github.com/ignaciojulio/Stellar-forge/issues/85) -* add pause/unpause admin function to factory contract ([#39](https://github.com/ignaciojulio/Stellar-forge/issues/39)) ([5a5c965](https://github.com/ignaciojulio/Stellar-forge/commit/5a5c9657eb01f741a73fd68b07e8c129c0b72494)) -* add polling, last-updated indicator, and refresh to transaction history ([ac79943](https://github.com/ignaciojulio/Stellar-forge/commit/ac799436d088dc8a3876b6b1f8f1f3bda7e57e9e)), closes [#752](https://github.com/ignaciojulio/Stellar-forge/issues/752) -* add Prettier, fix all TS errors, add CI/CD pipeline, add formatAddress and Checkbox UI component ([a11180e](https://github.com/ignaciojulio/Stellar-forge/commit/a11180e10be6c60a668889a4ca85c4056e65db23)) -* add PWA support with vite-plugin-pwa ([#81](https://github.com/ignaciojulio/Stellar-forge/issues/81)) ([547110c](https://github.com/ignaciojulio/Stellar-forge/commit/547110c7a3bf0b9308433e6541a72851315dbc7f)) -* add reentrancy guard to create_token with Error::Reentrancy variant ([986de4b](https://github.com/ignaciojulio/Stellar-forge/commit/986de4be908dde9aca2df9497827bd4e57c72188)) -* add reusable Modal base component ([#527](https://github.com/ignaciojulio/Stellar-forge/issues/527)) ([e19c519](https://github.com/ignaciojulio/Stellar-forge/commit/e19c519d5362139603878ae605d798d0f32d4885)) -* add reusable Modal base component ([#527](https://github.com/ignaciojulio/Stellar-forge/issues/527)) ([f605b53](https://github.com/ignaciojulio/Stellar-forge/commit/f605b537b184538356ec3f5dfaf6e77a7023ec68)) -* add robots.txt, sitemap.xml, and meta description for SEO ([de6bb1c](https://github.com/ignaciojulio/Stellar-forge/commit/de6bb1ca190af7144dbcf42c4e375fb037629e40)) -* add robust useClipboard hook and refactor dashboard ([7149392](https://github.com/ignaciojulio/Stellar-forge/commit/7149392879177afb4890d27e84fcafd74993380c)), closes [#26](https://github.com/ignaciojulio/Stellar-forge/issues/26) -* add secure Admin Panel for factory fee management ([39e28a5](https://github.com/ignaciojulio/Stellar-forge/commit/39e28a5d8ea44f66da35c9103d0283f8ebbca68a)) -* Add security disclosure policy ([#47](https://github.com/ignaciojulio/Stellar-forge/issues/47)) ([096fcd7](https://github.com/ignaciojulio/Stellar-forge/commit/096fcd7db59170ab86e51293dfd1c261de5b856c)) -* Add Select UI component with accessibility and dark mode support ([412420a](https://github.com/ignaciojulio/Stellar-forge/commit/412420aaf6de26d11d299790904564aada4d9982)) -* add semantic release for automated versioning ([bcd42fe](https://github.com/ignaciojulio/Stellar-forge/commit/bcd42fe4045889bb25e4c751a1999444d91b9e48)) -* add sitemap generation script and update prebuild script to include it ([8948663](https://github.com/ignaciojulio/Stellar-forge/commit/89486632614de04d357937eebec497dfcd8656bc)) -* add skeleton loaders and a11y improvements ([#475](https://github.com/ignaciojulio/Stellar-forge/issues/475), [#477](https://github.com/ignaciojulio/Stellar-forge/issues/477)) ([1ea1e54](https://github.com/ignaciojulio/Stellar-forge/commit/1ea1e54760f52c844e342691ade1968f9d9f3db4)) -* add skeleton loaders for TokenExplorer and Dashboard ([42867fe](https://github.com/ignaciojulio/Stellar-forge/commit/42867fe60d0626302ff16fe9f97da65e7ca44aa9)), closes [#735](https://github.com/ignaciojulio/Stellar-forge/issues/735) -* add skeleton-loaders spec (requirements, design, tasks) ([ec3a9ed](https://github.com/ignaciojulio/Stellar-forge/commit/ec3a9edccdea9cb861af1c086b32f0e45188e011)) -* add social sharing for newly created tokens ([#521](https://github.com/ignaciojulio/Stellar-forge/issues/521)) ([7e2cdcc](https://github.com/ignaciojulio/Stellar-forge/commit/7e2cdcc311980edab824795b7afb3fa37f5bf470)) -* add Soroban benchmark harness for resource cost tracking ([#968](https://github.com/ignaciojulio/Stellar-forge/issues/968)) ([91b504f](https://github.com/ignaciojulio/Stellar-forge/commit/91b504f5f459c5e5491cf181a30c00c4611bfb1d)), closes [#12](https://github.com/ignaciojulio/Stellar-forge/issues/12) -* add soroban-token-sdk audit spec ([ae3686a](https://github.com/ignaciojulio/Stellar-forge/commit/ae3686a6aa6a9ea90c65cdac09212cbc17484e50)) -* add stellar contract optimize to deployment workflow ([4a56338](https://github.com/ignaciojulio/Stellar-forge/commit/4a5633820d68a264160311da5c161e36fa3dec9d)) -* add stellarExplorerUrl utility and wire explorer links ([d043699](https://github.com/ignaciojulio/Stellar-forge/commit/d04369980cab1a6f5a29c557b4857fdec90d0b43)) -* add Storybook stories for ConfirmModal, ProgressIndicator, and InsufficientBalanceWarning ([a25343e](https://github.com/ignaciojulio/Stellar-forge/commit/a25343ef58f82389e1ee34d6e81304cf0bcba9c8)) -* add Storybook with stories for all UI components ([564a5b8](https://github.com/ignaciojulio/Stellar-forge/commit/564a5b8747b18cecec42b800a28dd3b4845a51e6)) -* add Terms of Service acceptance modal before first transaction ([#529](https://github.com/ignaciojulio/Stellar-forge/issues/529)) ([53a7bc8](https://github.com/ignaciojulio/Stellar-forge/commit/53a7bc8473d5bfc7ddc0b4c8bb6b34d28c6f0b10)) -* add Terms of Service acceptance modal before first transaction ([#529](https://github.com/ignaciojulio/Stellar-forge/issues/529)) ([b2ddf76](https://github.com/ignaciojulio/Stellar-forge/commit/b2ddf76f997e7098519c2db85ef732176cc34ecf)) -* add testnet faucet integration via Friendbot ([#519](https://github.com/ignaciojulio/Stellar-forge/issues/519)) ([f7c2965](https://github.com/ignaciojulio/Stellar-forge/commit/f7c29653018bc9422437a517de60b021c9d9fd94)) -* add token event history with pagination and event details display ([9196fdf](https://github.com/ignaciojulio/Stellar-forge/commit/9196fdfa879502ba361811ad750a45319afee0e4)) -* add token search, filter, and sort to Dashboard ([a17250a](https://github.com/ignaciojulio/Stellar-forge/commit/a17250a7e7415c736f7abfb26c24ad63cce35e51)) -* add token search, filter, and sort to dashboard ([#64](https://github.com/ignaciojulio/Stellar-forge/issues/64)) ([eb80749](https://github.com/ignaciojulio/Stellar-forge/commit/eb80749f6deacb0dab54ba40af95e1d1693cdb81)) -* add TokenDashboard with pagination, search, and Explorer links ([d7ce574](https://github.com/ignaciojulio/Stellar-forge/commit/d7ce574bcb1e0b4670e1cc9c2d895946776aaf1a)) -* add TokenExplorer component with search and pagination ([4b21179](https://github.com/ignaciojulio/Stellar-forge/commit/4b211798c41fbfb492613f48e66a6bb174a37da1)) -* add TokenMetadata display component ([658efc0](https://github.com/ignaciojulio/Stellar-forge/commit/658efc0c1321a6b4794c0682e75894e0a45e66aa)) -* Add transaction retry logic with exponential backoff ([#62](https://github.com/ignaciojulio/Stellar-forge/issues/62)) ([f0d8f02](https://github.com/ignaciojulio/Stellar-forge/commit/f0d8f02c2d45a8649b21ef2a83f69fc757033bba)) -* Add TransactionHistory component and useTransactionHistory hook for Stellar token operations ([f8fed91](https://github.com/ignaciojulio/Stellar-forge/commit/f8fed914347008992fae259b506952c2d0c7ae88)) -* Add TransactionStatus component and tests ([4637fb8](https://github.com/ignaciojulio/Stellar-forge/commit/4637fb8c495482a5609f2f90ea6a5309aa09dd57)) -* add transfer_admin function with tests ([347d54f](https://github.com/ignaciojulio/Stellar-forge/commit/347d54fbbf885985964f991d51ed4c6807dcd071)) -* add TTL management for all Soroban storage writes ([7b34532](https://github.com/ignaciojulio/Stellar-forge/commit/7b3453265f83cbc0fe7f0dcaf8a736f21902887c)) -* add UI barrel export and update all imports ([2e4fbe0](https://github.com/ignaciojulio/Stellar-forge/commit/2e4fbe0e006564fee5c51396ba9137e9de42793c)) -* add update_admin function to token factory contract ([#479](https://github.com/ignaciojulio/Stellar-forge/issues/479)) ([5db1fe4](https://github.com/ignaciojulio/Stellar-forge/commit/5db1fe4734dc41788232efd3e11397bf74bd2954)) -* add useDebounce hook, apply to MintForm/BurnForm/Dashboard, fix build ([e8727e1](https://github.com/ignaciojulio/Stellar-forge/commit/e8727e16b4f1c50beca6977389720fe1497b192b)) -* add useFactoryState hook, coverage thresholds, and CI workflow ([15b366d](https://github.com/ignaciojulio/Stellar-forge/commit/15b366d315366e901a05351e7d200da9330bd39d)) -* Add useLocalStorage hook and tests ([56eac71](https://github.com/ignaciojulio/Stellar-forge/commit/56eac719547fd75bdd916da05ab5a8bcde6fc663)) -* add useTokenBalance hook and fix TypeScript errors ([43792b7](https://github.com/ignaciojulio/Stellar-forge/commit/43792b7593c29fff7929ca1c52e9096b32c4e3ef)) -* add useTokens pagination and useTokenInfo hook ([a473194](https://github.com/ignaciojulio/Stellar-forge/commit/a473194fbf697aa6feeed853de1253c30d8947df)) -* add VITE_TOKEN_WASM_HASH to env validation and fix duplicate import ([b027cc2](https://github.com/ignaciojulio/Stellar-forge/commit/b027cc256bc2c3381cedcfab7b48a81805e7f41f)) -* add wallet token portfolio dashboard ([cc28ab9](https://github.com/ignaciojulio/Stellar-forge/commit/cc28ab9f2d9505077bfbc430aac870983c6979f7)) -* add WalletButton UI component and integrate into App.tsx header ([cf20f69](https://github.com/ignaciojulio/Stellar-forge/commit/cf20f695cb93d60d96fa4f5f1592f1395ac2ef4f)) -* add wasm-opt post-processing for contract binary ([de1f779](https://github.com/ignaciojulio/Stellar-forge/commit/de1f779897d4ddbc938d9d1d58e1020d352081a0)) -* add whitelist for fee-free token creation ([59c0f59](https://github.com/ignaciojulio/Stellar-forge/commit/59c0f598ecfd74fa1cfe5a036a8ac22418e0d823)) -* **api:** add off-chain contract event indexer ([#943](https://github.com/ignaciojulio/Stellar-forge/issues/943)) ([19a9544](https://github.com/ignaciojulio/Stellar-forge/commit/19a9544f64827539f6c763c7f9c5b0df725b3cf0)) -* **api:** persist contract events in the indexer store (supersedes [#1138](https://github.com/ignaciojulio/Stellar-forge/issues/1138)) ([#1154](https://github.com/ignaciojulio/Stellar-forge/issues/1154)) ([45ad5bc](https://github.com/ignaciojulio/Stellar-forge/commit/45ad5bc0af5d6a8079746f03ff2399fc47be653b)) -* build token creation form UI on home page ([#667](https://github.com/ignaciojulio/Stellar-forge/issues/667)) ([0311381](https://github.com/ignaciojulio/Stellar-forge/commit/03113810e45d1c622661e7b3e6a9d19222d302a1)) -* Burn Tokens UI with danger-zone styling and safety confirmation ([#675](https://github.com/ignaciojulio/Stellar-forge/issues/675)) ([f894e11](https://github.com/ignaciojulio/Stellar-forge/commit/f894e116c013786ca1ddd4bce9a7af607a96c418)) -* **burn:** add data-testid attributes for balance display, Max button, and validation error ([0c72f14](https://github.com/ignaciojulio/Stellar-forge/commit/0c72f141647c5c6b77faca6fbd4ea22c696d4b5e)), closes [#755](https://github.com/ignaciojulio/Stellar-forge/issues/755) [#755](https://github.com/ignaciojulio/Stellar-forge/issues/755) -* **ci:** add access-control documentation drift check ([#1112](https://github.com/ignaciojulio/Stellar-forge/issues/1112)) ([#1148](https://github.com/ignaciojulio/Stellar-forge/issues/1148)) ([7b41cfd](https://github.com/ignaciojulio/Stellar-forge/commit/7b41cfda11bb62a91fc6bbcfbfd5bf3063f69f9f)) -* **ci:** add reproducible WASM hash verification workflow for mainnet deployments ([#950](https://github.com/ignaciojulio/Stellar-forge/issues/950)) ([abcdbce](https://github.com/ignaciojulio/Stellar-forge/commit/abcdbceaf28f24c23aaa963bf69c9a0b27b47fd5)), closes [#940](https://github.com/ignaciojulio/Stellar-forge/issues/940) -* comprehensive contract tests + fix lib.rs compilation errors ([#677](https://github.com/ignaciojulio/Stellar-forge/issues/677)) ([83a8f8f](https://github.com/ignaciojulio/Stellar-forge/commit/83a8f8f55ddbdd49046ce8ddb84be53360e16699)) -* **contract:** add batch token creation ([#487](https://github.com/ignaciojulio/Stellar-forge/issues/487)) ([b50b182](https://github.com/ignaciojulio/Stellar-forge/commit/b50b18207842a21052d69f1a85c67f893e36231a)) -* **contract:** add optional max supply cap to tokens ([#483](https://github.com/ignaciojulio/Stellar-forge/issues/483)) ([dc00eb6](https://github.com/ignaciojulio/Stellar-forge/commit/dc00eb6f44e00cdc437c4824c474cb227837dfef)) -* **contract:** add treasury fee split mechanism ([#485](https://github.com/ignaciojulio/Stellar-forge/issues/485)) ([d933acf](https://github.com/ignaciojulio/Stellar-forge/commit/d933acfc8876eb3f0db155a0ec7149d04bc2b323)) -* **contract:** emit events for all state-changing functions ([#482](https://github.com/ignaciojulio/Stellar-forge/issues/482)) ([0a375a8](https://github.com/ignaciojulio/Stellar-forge/commit/0a375a8a115d2c580d2c1e801e6936102eba4d19)) -* **contracts:** add schema versioning and implement migrate ([7293485](https://github.com/ignaciojulio/Stellar-forge/commit/7293485078366ff93f43ebb358360ad335dbde12)) -* **contracts:** add schema versioning and implement migrate ([a9fbd2e](https://github.com/ignaciojulio/Stellar-forge/commit/a9fbd2e525ce9f459d28cfdbc126c3a50ab68919)) -* create WalletConnectButton component ([766c6b9](https://github.com/ignaciojulio/Stellar-forge/commit/766c6b92eb995d711458cf20585591120ced5d91)) -* enable TypeScript strict mode ([#531](https://github.com/ignaciojulio/Stellar-forge/issues/531)) ([bb3ad84](https://github.com/ignaciojulio/Stellar-forge/commit/bb3ad84b61317ddca30bc365f9eb93d4bfc76b28)) -* enforce u128 for initial_supply and add InvalidTokenParams validation [#517](https://github.com/ignaciojulio/Stellar-forge/issues/517) ([67582a3](https://github.com/ignaciojulio/Stellar-forge/commit/67582a37491bb016ab44a09f6539321b776a29d0)) -* enhance security, add contract upgrade support, and integrate E2E tests into CI ([5695ca0](https://github.com/ignaciojulio/Stellar-forge/commit/5695ca0f03c7e7473d50b32cc8be6ca7c41ea560)) -* enhance token factory with DataKey enum and update storage access ([e0c24c0](https://github.com/ignaciojulio/Stellar-forge/commit/e0c24c04b0f0a9c6b9ea74afd0778915d2256a6f)) -* **explorer:** add Stellar Expert deep links for accounts, transactions, and contracts ([6d509a4](https://github.com/ignaciojulio/Stellar-forge/commit/6d509a4719802c15ba7a25454bd1cb63e51f4fdc)) -* extract contract error mapping to contractErrors.ts ([0420e56](https://github.com/ignaciojulio/Stellar-forge/commit/0420e56d1fa61c2f6923fd51f34e199f9d0aa058)) -* **factory:** add offset/limit pagination to get_tokens_by_creator ([#729](https://github.com/ignaciojulio/Stellar-forge/issues/729)) ([3f88aae](https://github.com/ignaciojulio/Stellar-forge/commit/3f88aaeb44917ccbcc07bfa5bb6c8fa8c69f1bec)) -* **frontend:** add ipfs gateway URL resolver and stabilize frontend checks ([005ff3f](https://github.com/ignaciojulio/Stellar-forge/commit/005ff3f36d8e792c1aae283a908f8e34f4540440)) -* **frontend:** block writes on network mismatch in metadata + admin forms ([#906](https://github.com/ignaciojulio/Stellar-forge/issues/906)) ([f6e88f3](https://github.com/ignaciojulio/Stellar-forge/commit/f6e88f390e3f87e5abd34ce35989c5907b83bd98)) -* **frontend:** implement i18n support with es and pt translations ([dcbc1b2](https://github.com/ignaciojulio/Stellar-forge/commit/dcbc1b2838650f7d285d92ffec61a226f0dd28df)) -* **frontend:** implement paginated global token listing (getAllTokens) ([#1028](https://github.com/ignaciojulio/Stellar-forge/issues/1028)) ([0e1b51e](https://github.com/ignaciojulio/Stellar-forge/commit/0e1b51e2590b3c23468f893f13e77e5f2eeb592a)), closes [#1017](https://github.com/ignaciojulio/Stellar-forge/issues/1017) -* **frontend:** verify deployed token WASM hash against factory state ([#986](https://github.com/ignaciojulio/Stellar-forge/issues/986)) ([6d1566a](https://github.com/ignaciojulio/Stellar-forge/commit/6d1566a8416e1ac44860fbb6a1395e062548141a)), closes [#925](https://github.com/ignaciojulio/Stellar-forge/issues/925) [hi#severity](https://github.com/hi/issues/severity) [#982](https://github.com/ignaciojulio/Stellar-forge/issues/982) [#984](https://github.com/ignaciojulio/Stellar-forge/issues/984) [#984](https://github.com/ignaciojulio/Stellar-forge/issues/984) [#984](https://github.com/ignaciojulio/Stellar-forge/issues/984) [#982](https://github.com/ignaciojulio/Stellar-forge/issues/982) -* **frontend:** wire network-mismatch banner + FAQ page, drop dead duplicate, fix repo URLs ([901021f](https://github.com/ignaciojulio/Stellar-forge/commit/901021f9ce8eac98d3d50bf5970006818bd835f8)) -* gate wallet and metadata actions behind ToS ([8318679](https://github.com/ignaciojulio/Stellar-forge/commit/8318679a05a77d2324ef1032e5a8735df50de38b)) -* global error boundary, toast system, and service error cleanup ([19dbf05](https://github.com/ignaciojulio/Stellar-forge/commit/19dbf055d8666ad6c29cfb08330d54dba1c37da2)) -* global error boundary, toast system, and service error cleanup ([6ca83ad](https://github.com/ignaciojulio/Stellar-forge/commit/6ca83ad43e48b722d1decf01505c7df900926b39)) -* **hooks:** add LRU eviction to useTokens module-level cache ([#967](https://github.com/ignaciojulio/Stellar-forge/issues/967)) ([25ca799](https://github.com/ignaciojulio/Stellar-forge/commit/25ca799e4b03c97a3d52752f7ccbdda0e0820816)) -* **hooks:** add useTransaction hook for transaction lifecycle ([#489](https://github.com/ignaciojulio/Stellar-forge/issues/489)) ([18debc3](https://github.com/ignaciojulio/Stellar-forge/commit/18debc33c6bc0dd55ebb830be061c32663b9b2bd)) -* implement BigInt-safe formatting utilities ([fc30b37](https://github.com/ignaciojulio/Stellar-forge/commit/fc30b3739e3829c47c164b5fc3ed766a720160e7)) -* implement burn_enabled per-token flag ([7d265e8](https://github.com/ignaciojulio/Stellar-forge/commit/7d265e844a3490af982d1665e0d6d17287a21ad1)) -* Implement Freighter Wallet Integration ([b91a66e](https://github.com/ignaciojulio/Stellar-forge/commit/b91a66ea7d8ca5e98b04da98c036bde9103896a8)) -* implement Freighter wallet integration ([#666](https://github.com/ignaciojulio/Stellar-forge/issues/666)) ([8416cfd](https://github.com/ignaciojulio/Stellar-forge/commit/8416cfd8dd76863b1142ec6662bd063a5eb5c2c8)) -* implement global error boundary ([#473](https://github.com/ignaciojulio/Stellar-forge/issues/473)) ([d83fe50](https://github.com/ignaciojulio/Stellar-forge/commit/d83fe50a891c8e6b0ddf9657f533068d85ae8d9d)) -* implement Horizon API retry logic with exponential backoff and Retry-After handling [#499](https://github.com/ignaciojulio/Stellar-forge/issues/499) ([cfd31b5](https://github.com/ignaciojulio/Stellar-forge/commit/cfd31b5b7d3cb95c5a4ac367ed93ec95da884a5f)) -* implement mobile-responsive design for all components ([cfdf285](https://github.com/ignaciojulio/Stellar-forge/commit/cfdf285acfd73648d3ddb9189c9603994e422016)) -* implement pagination for token dashboard ([#29](https://github.com/ignaciojulio/Stellar-forge/issues/29)) ([9aa41b1](https://github.com/ignaciojulio/Stellar-forge/commit/9aa41b1489fc9a4b07d3be68c6f2521197a402f0)) -* implement Pinata IPFS upload service with tests ([6b33365](https://github.com/ignaciojulio/Stellar-forge/commit/6b33365592b88e4835ff4b0728bfd33fe5c65504)) -* implement Pinata IPFS upload with progress tracking and error handling ([53b3684](https://github.com/ignaciojulio/Stellar-forge/commit/53b368444cefd75a4ab1ae0ad0856244b78d0d59)) -* implement responsive mobile layout (issue [#616](https://github.com/ignaciojulio/Stellar-forge/issues/616)) ([49ddf41](https://github.com/ignaciojulio/Stellar-forge/commit/49ddf41412597f035283a56ce005728838a7bf8e)) -* implement reusable CopyButton component with Clipboard API integration ([2f8b716](https://github.com/ignaciojulio/Stellar-forge/commit/2f8b71673d4bcfed75cea83aba41ba75c7d39d59)) -* implement Soroban contract invocation logic in StellarService ([3a4af37](https://github.com/ignaciojulio/Stellar-forge/commit/3a4af37b668bc7dd633dca8f80ab34230a160da8)) -* implement Soroban RPC interactions in stellar.ts ([42c9d18](https://github.com/ignaciojulio/Stellar-forge/commit/42c9d18240eccc884dcee88d0e56e1897fe2a7de)) -* implement StellarService with full Soroban RPC integration ([3f0a520](https://github.com/ignaciojulio/Stellar-forge/commit/3f0a52060e1264e34239d59ede6542c9a2791bf6)) -* implement token burn UI and service ([a199523](https://github.com/ignaciojulio/Stellar-forge/commit/a19952319a4e6efc77ccf128bd72ac0fe6fdc2e3)) -* implement Token Dashboard page ([#673](https://github.com/ignaciojulio/Stellar-forge/issues/673)) ([c3b204c](https://github.com/ignaciojulio/Stellar-forge/commit/c3b204c15fcca7827fd91c69f97cc0708395e3a8)) -* implement token detail page ([a79ef19](https://github.com/ignaciojulio/Stellar-forge/commit/a79ef19b62d87c742306511e4c6d4194f47f4301)) -* implement TokenDashboard page with TokenCard component and index-based pagination ([4af373b](https://github.com/ignaciojulio/Stellar-forge/commit/4af373b0d6ae3928d8c9f09f6fec2e181c1fd857)) -* implement TokenDetail page ([#470](https://github.com/ignaciojulio/Stellar-forge/issues/470)) ([71ca751](https://github.com/ignaciojulio/Stellar-forge/commit/71ca75186290f61636b5217b0e4817d8d70d5860)) -* implement TokenDetail page with IPFS metadata, mint/burn/set-metadata inline forms, and 404 state ([9c7f0eb](https://github.com/ignaciojulio/Stellar-forge/commit/9c7f0eb21f1218f5ad84e0026eb007b6760fcf49)) -* implement transaction status tracking ([#681](https://github.com/ignaciojulio/Stellar-forge/issues/681)) ([3c0a793](https://github.com/ignaciojulio/Stellar-forge/commit/3c0a79320128a7e0ebe31f2c6c2091dedbabc790)) -* implement update_treasury in token-factory ([0c381d3](https://github.com/ignaciojulio/Stellar-forge/commit/0c381d364fc58b048d6ac3b5a3c8e2fdb014a4d4)) -* implement useLocalStorage for dark mode context and add tests for useDarkMode hook ([f04664c](https://github.com/ignaciojulio/Stellar-forge/commit/f04664cf78bf2f23ca284ae6d8f7807432928a30)) -* implement useLocalStorage hook and integrate for Dark Mode, Network, and Language [#518](https://github.com/ignaciojulio/Stellar-forge/issues/518) ([9a25f84](https://github.com/ignaciojulio/Stellar-forge/commit/9a25f843fb0e4aa8c1cd12c84a1e045243386228)) -* implement useTokens hook with parallel fetching and cache ([d9cc12d](https://github.com/ignaciojulio/Stellar-forge/commit/d9cc12d47d2b1f03c90a062a7a4c43e5a8b9d16f)), closes [#16](https://github.com/ignaciojulio/Stellar-forge/issues/16) -* implement wallet auto-reconnect and Freighter event listeners ([4cba9dc](https://github.com/ignaciojulio/Stellar-forge/commit/4cba9dc763125c9a8fa920a14aa94eb91f241835)) -* integrate Sentry error tracking for failed contract calls ([e0cb9f9](https://github.com/ignaciojulio/Stellar-forge/commit/e0cb9f995c7d04606937ca8c1df0cd923e71c96d)), closes [#757](https://github.com/ignaciojulio/Stellar-forge/issues/757) -* **ipfs:** implement IPFS metadata upload via Pinata ([#669](https://github.com/ignaciojulio/Stellar-forge/issues/669)) ([949bcc3](https://github.com/ignaciojulio/Stellar-forge/commit/949bcc3dc44b247c9fc084edd83cac814a510dd2)) -* Mint Tokens UI with RHF validation and token dropdown ([#674](https://github.com/ignaciojulio/Stellar-forge/issues/674)) ([223235d](https://github.com/ignaciojulio/Stellar-forge/commit/223235d8b6d6995d04610e0103b44853d267c4f4)) -* mobile responsive design ([90814c2](https://github.com/ignaciojulio/Stellar-forge/commit/90814c291d43fc2cc5cb1082eaedb49d70b8f228)) -* **monitoring:** add monitoring docs and sentry dependency ([e043a5c](https://github.com/ignaciojulio/Stellar-forge/commit/e043a5c4778490cdc5f61a5a6a8bec84f04a97e0)) -* **monitoring:** add Sentry, uptime monitoring, and health endpoint ([cee6369](https://github.com/ignaciojulio/Stellar-forge/commit/cee6369984c5aa792f631cb2d99f5387f523a675)) -* move wallet state to global React Context ([6c24340](https://github.com/ignaciojulio/Stellar-forge/commit/6c243409493ecaf75dcaf7020b07e51fa764489e)) -* network switcher with mainnet warning and localStorage persistence ([5fa8531](https://github.com/ignaciojulio/Stellar-forge/commit/5fa8531fe7735ea781dfdcc3d0393e43b2392138)) -* pause/unpause factory already implemented; add burn-while-paused test ([#480](https://github.com/ignaciojulio/Stellar-forge/issues/480)) ([4dd54ca](https://github.com/ignaciojulio/Stellar-forge/commit/4dd54cae186d0f659b02c09174ef52b8c45d40bd)) -* provide services via StellarContext, re-init on network change ([4f924de](https://github.com/ignaciojulio/Stellar-forge/commit/4f924de5f21060928b716c73263e9dde08eb6232)) -* **security:** add Content Security Policy and security headers ([19f0f1f](https://github.com/ignaciojulio/Stellar-forge/commit/19f0f1f1a414ff3aaa40c7d880892ae53d0fb494)) -* **security:** add dependency audit and Dependabot configuration ([9f404c1](https://github.com/ignaciojulio/Stellar-forge/commit/9f404c125b296e2693acefd67f2e6c0c1476f987)), closes [hi#severity](https://github.com/hi/issues/severity) [#502](https://github.com/ignaciojulio/Stellar-forge/issues/502) -* **security:** add strict CSP, X-Frame-Options, and X-Content-Type-Options headers ([a625191](https://github.com/ignaciojulio/Stellar-forge/commit/a625191242ad136c2f085d1524916a0781bbc0ea)) -* **security:** add triage and waiver workflow for audit findings ([#981](https://github.com/ignaciojulio/Stellar-forge/issues/981)) ([aa0ceab](https://github.com/ignaciojulio/Stellar-forge/commit/aa0ceab6d134bb7706f4bdb03f4e591bc5eba1ee)), closes [hi#or-above](https://github.com/hi/issues/or-above) [#939](https://github.com/ignaciojulio/Stellar-forge/issues/939) -* show pre-signature fee recipient breakdown and batch total (Closes [#1108](https://github.com/ignaciojulio/Stellar-forge/issues/1108)) ([#1124](https://github.com/ignaciojulio/Stellar-forge/issues/1124)) ([f983539](https://github.com/ignaciojulio/Stellar-forge/commit/f983539afe0eccc35503bc0a0378e47f0f0d70de)) -* show XLM/USD equivalent in FeeDisplay component ([fd3c20d](https://github.com/ignaciojulio/Stellar-forge/commit/fd3c20d6172b5f12542e4822efc0e193e64b9f37)), closes [#733](https://github.com/ignaciojulio/Stellar-forge/issues/733) -* toast notification system already implemented ([#474](https://github.com/ignaciojulio/Stellar-forge/issues/474)) ([73b04c9](https://github.com/ignaciojulio/Stellar-forge/commit/73b04c93422a042df4c9343a024b0d799f062b65)) -* **token-factory:** validate create_token params and use InvalidParameters error ([4e7abc4](https://github.com/ignaciojulio/Stellar-forge/commit/4e7abc445ef9bb859033a1154087f4e06c60d426)) -* **ui:** add DropZone drag-and-drop component and replace file input in MetadataUploadForm ([fee9791](https://github.com/ignaciojulio/Stellar-forge/commit/fee979106b6aa2f6cabdae7a8d89e34187fb4516)) -* **ui:** add network-aware Stellar Expert explorer links ([20dced8](https://github.com/ignaciojulio/Stellar-forge/commit/20dced85535f61c3700295b38486148e21fcee85)), closes [#621](https://github.com/ignaciojulio/Stellar-forge/issues/621) -* **ui:** confirmation modal before every state-changing transaction ([#490](https://github.com/ignaciojulio/Stellar-forge/issues/490)) ([88291e3](https://github.com/ignaciojulio/Stellar-forge/commit/88291e3a54fb6581068f0aa474301effc8d5839f)) -* **ui:** implement MetadataForm with IPFS upload + Stellar linking ([#676](https://github.com/ignaciojulio/Stellar-forge/issues/676)) ([20f5327](https://github.com/ignaciojulio/Stellar-forge/commit/20f53270a24aafadba31984dde41b3b1f4605ad7)) -* upgrade mechanism, ADRs, QR code sharing, onboarding tutorial ([7b59535](https://github.com/ignaciojulio/Stellar-forge/commit/7b5953553e50e0d011aefd8d581d346cd03eef0d)), closes [#1](https://github.com/ignaciojulio/Stellar-forge/issues/1) [#2](https://github.com/ignaciojulio/Stellar-forge/issues/2) [#3](https://github.com/ignaciojulio/Stellar-forge/issues/3) [#4](https://github.com/ignaciojulio/Stellar-forge/issues/4) -* **ux:** insufficient balance warning before transaction submission ([#496](https://github.com/ignaciojulio/Stellar-forge/issues/496)) ([0777d93](https://github.com/ignaciojulio/Stellar-forge/commit/0777d937bf16c0428cc0c9b8981bcf6322cfba66)) -* wire setMetadata to StellarService in TokenDetail ([04de946](https://github.com/ignaciojulio/Stellar-forge/commit/04de946b9f1be0b11b385f12dd0138798cb79437)) -* wire up mint and burn token UI to contract ([ca6b7b4](https://github.com/ignaciojulio/Stellar-forge/commit/ca6b7b41537ff00ac62d56316089355f62a6b188)), closes [#541](https://github.com/ignaciojulio/Stellar-forge/issues/541) - +- **#588:** Build Token Creation Form UI ([b13478c](https://github.com/ignaciojulio/Stellar-forge/commit/b13478ce4ce5f7f5ff75bd629ee82c8e77c6e00b)), closes [#588](https://github.com/ignaciojulio/Stellar-forge/issues/588) +- **#589:** Implement StellarService Token Deployment ([b186936](https://github.com/ignaciojulio/Stellar-forge/commit/b18693646c7a9a6826cae19aef04b6b97fe95e16)), closes [#589](https://github.com/ignaciojulio/Stellar-forge/issues/589) +- **#590:** Implement IPFS Metadata Upload via Pinata ([98e1fc0](https://github.com/ignaciojulio/Stellar-forge/commit/98e1fc05522b123fdfba8949d4f891d09ca36315)), closes [#590](https://github.com/ignaciojulio/Stellar-forge/issues/590) +- **#603:** Create Token Detail Page ([a1aa1ec](https://github.com/ignaciojulio/Stellar-forge/commit/a1aa1ecd6ccad4ec4e2b00a59e706cff4b133c13)), closes [#603](https://github.com/ignaciojulio/Stellar-forge/issues/603) +- **#604:** Add React Router for Navigation ([be195b5](https://github.com/ignaciojulio/Stellar-forge/commit/be195b50249bb8d3cfe632338b279ccbab3078c1)), closes [#604](https://github.com/ignaciojulio/Stellar-forge/issues/604) +- **#606:** Add loading states and skeleton UI ([41111e0](https://github.com/ignaciojulio/Stellar-forge/commit/41111e0675574976efd551268375a5f5aafa094e)), closes [#606](https://github.com/ignaciojulio/Stellar-forge/issues/606) +- **#607:** Add environment variable validation on startup ([5e3ff84](https://github.com/ignaciojulio/Stellar-forge/commit/5e3ff842dee16505f089da8fa8ddf59ff1cbf0aa)), closes [#607](https://github.com/ignaciojulio/Stellar-forge/issues/607) +- **#734:** Add debounced search and creator address filter to TokenExplorer ([12c703b](https://github.com/ignaciojulio/Stellar-forge/commit/12c703bf6f4ef881be1aec3fb7a31659182a05fb)), closes [#734](https://github.com/ignaciojulio/Stellar-forge/issues/734) +- **#fuzz:** add fuzz targets for set_metadata and mint_tokens ([167432d](https://github.com/ignaciojulio/Stellar-forge/commit/167432dc36b3a44d2fa2b3bcd891af976dc06ab6)), closes [#fuzz](https://github.com/ignaciojulio/Stellar-forge/issues/fuzz) +- **a11y:** accessibility audit and fixes ([98eb2f7](https://github.com/ignaciojulio/Stellar-forge/commit/98eb2f7bce43199095257b3f21b29347db71fb7d)) +- add accessibility improvements (a11y) ([259d1b0](https://github.com/ignaciojulio/Stellar-forge/commit/259d1b0ba239906605b10feb7a151deea01bb70b)) +- add AddressDisplay component with copy and explorer link ([2ab3bda](https://github.com/ignaciojulio/Stellar-forge/commit/2ab3bdaa16ba838f6da55e681983df940707cb31)) +- add analytics integration spec and scaffolding ([#522](https://github.com/ignaciojulio/Stellar-forge/issues/522)) ([e4d8902](https://github.com/ignaciojulio/Stellar-forge/commit/e4d89029fe13ea8a94a574bc2028f9090bc51cc0)) +- add CHANGELOG.md and PR template with changelog checklist ([89bb67e](https://github.com/ignaciojulio/Stellar-forge/commit/89bb67ed0b73c25e9a0fad46554b8ee6c35e17cb)) +- add client-side CID verification for metadata integrity ([#1139](https://github.com/ignaciojulio/Stellar-forge/issues/1139)) ([82e9a1b](https://github.com/ignaciojulio/Stellar-forge/commit/82e9a1b72bf1c78efede6522669d40707a5f295c)) +- add client-side routing with react-router-dom (fixes [#471](https://github.com/ignaciojulio/Stellar-forge/issues/471)) ([baee94d](https://github.com/ignaciojulio/Stellar-forge/commit/baee94d5865dea41be3e3a0caa3a70952c8f45b3)) +- add comprehensive error handling system ([62b4348](https://github.com/ignaciojulio/Stellar-forge/commit/62b43485f363fcdd348e518631221dcdedbca452)) +- add ConfirmModal before all on-chain transactions ([3cef134](https://github.com/ignaciojulio/Stellar-forge/commit/3cef134598c07ec70c6c8d7ed84549da9a0c6162)) +- add Content-Security-Policy headers ([ef28578](https://github.com/ignaciojulio/Stellar-forge/commit/ef285786231bd883fab9b5e4f2e369658cb010b4)) +- add contract event history with pagination ([0425f56](https://github.com/ignaciojulio/Stellar-forge/commit/0425f560eb14fe3ab740e9e1726e045d9259772a)) +- add contract event indexing spec ([#612](https://github.com/ignaciojulio/Stellar-forge/issues/612)) ([5952c01](https://github.com/ignaciojulio/Stellar-forge/commit/5952c015de58f01b79a0a3978f7baa09e1ec8c4c)) +- add CopyButton component and integrations [#491](https://github.com/ignaciojulio/Stellar-forge/issues/491) ([6d16970](https://github.com/ignaciojulio/Stellar-forge/commit/6d1697051d31d6876a50008a3d7669f69d5315b6)) +- add dark mode support with localStorage persistence ([24e96e5](https://github.com/ignaciojulio/Stellar-forge/commit/24e96e584e68fdf5177d3631d5172f390ed08465)) +- add dark mode with system preference, localStorage persistence, and toggle button ([5658728](https://github.com/ignaciojulio/Stellar-forge/commit/5658728f0ba9b5825e3f002c10a8a381c4434ced)) +- add decimals validation for create_token (0-18 inclusive) ([f88ec3c](https://github.com/ignaciojulio/Stellar-forge/commit/f88ec3c3e3100c34bb383c6b90a92fcb1fd33cc4)), closes [#515](https://github.com/ignaciojulio/Stellar-forge/issues/515) +- add deploy-contract.sh script for automated contract deployment ([f478eb2](https://github.com/ignaciojulio/Stellar-forge/commit/f478eb2f264a2ad65366be6217dd897ab5ca1e26)) +- add E2E coverage for network mismatch guard across all write forms Closes [#935](https://github.com/ignaciojulio/Stellar-forge/issues/935) ([#970](https://github.com/ignaciojulio/Stellar-forge/issues/970)) ([a644ce6](https://github.com/ignaciojulio/Stellar-forge/commit/a644ce657163e43308840ecb8e4a5582b7046cf7)) +- add env variable validation and configuration guide ([98642d9](https://github.com/ignaciojulio/Stellar-forge/commit/98642d9dd07b242b72fa17f7c71c90749209cf71)), closes [#8](https://github.com/ignaciojulio/Stellar-forge/issues/8) +- add ErrorBoundary component to catch render errors ([d297816](https://github.com/ignaciojulio/Stellar-forge/commit/d29781600265a3afc90e905556a2b1c995f2dd29)) +- add eslint import order rule spec ([ca4bc6b](https://github.com/ignaciojulio/Stellar-forge/commit/ca4bc6bad5f926f67845006654a62d413a8d7446)) +- add export CSV functionality to TransactionHistory ([637dc7c](https://github.com/ignaciojulio/Stellar-forge/commit/637dc7cfdb0c15520196983a6f5a87e0504fe0a1)) +- add fee bump transaction support ([#63](https://github.com/ignaciojulio/Stellar-forge/issues/63)) ([9b2b8ea](https://github.com/ignaciojulio/Stellar-forge/commit/9b2b8ea83cad398c574e53d1b5e50876c58252e7)) +- add FeeDisplay component with module-level cache ([e749987](https://github.com/ignaciojulio/Stellar-forge/commit/e749987653db420fb5261cbe857fb557a697ecd1)) +- add formatTimestamp and timeAgo utilities (#issue) ([02f8f30](https://github.com/ignaciojulio/Stellar-forge/commit/02f8f308f23c64b660d3419496b21085f9f35059)), closes [#issue](https://github.com/ignaciojulio/Stellar-forge/issues/issue) +- add formatTokenAmount and parseTokenAmount utilities ([1041ada](https://github.com/ignaciojulio/Stellar-forge/commit/1041ada734af076be7fd095d40e6c87ab39b58ed)) +- add French (fr) locale i18n support ([4429f89](https://github.com/ignaciojulio/Stellar-forge/commit/4429f898c5906e2f42b38d3b3069af5acf8b07bd)), closes [#740](https://github.com/ignaciojulio/Stellar-forge/issues/740) +- add friendbot banner for testnet ([aece4cb](https://github.com/ignaciojulio/Stellar-forge/commit/aece4cb99d882cf89cd6e87ba8a97312300ead57)) +- add frontend unit tests and fix retry unhandled rejections ([ec4b78b](https://github.com/ignaciojulio/Stellar-forge/commit/ec4b78b50b9ce92b0c37c64e705b0bd81a0f5f10)), closes [#9](https://github.com/ignaciojulio/Stellar-forge/issues/9) +- add frontend unit tests for validation utils ([#609](https://github.com/ignaciojulio/Stellar-forge/issues/609)) ([5ef4995](https://github.com/ignaciojulio/Stellar-forge/commit/5ef4995f2fce86123490a70b7a320a21ef5cdd19)) +- add get_tokens_by_creator view function ([#38](https://github.com/ignaciojulio/Stellar-forge/issues/38)) ([17b7ae0](https://github.com/ignaciojulio/Stellar-forge/commit/17b7ae09f4e8bca9660d61389704a18eab50a42f)) +- add global toast notification system ([ea22272](https://github.com/ignaciojulio/Stellar-forge/commit/ea22272f16cffdd0390b85ceb56a54fd0fbf519e)) +- Add husky + lint-staged pre-commit hooks ([#59](https://github.com/ignaciojulio/Stellar-forge/issues/59)) ([b11c468](https://github.com/ignaciojulio/Stellar-forge/commit/b11c4682e0bf0fbcf4b9885237b135142211c366)) +- add Husky pre-commit and pre-push hooks ([#533](https://github.com/ignaciojulio/Stellar-forge/issues/533)) ([c232169](https://github.com/ignaciojulio/Stellar-forge/commit/c232169967c5bcf58d07aeb4885efeed39444ce0)) +- add i18n foundation with react-i18next ([0f8c270](https://github.com/ignaciojulio/Stellar-forge/commit/0f8c2706990f5b6b6ce9f4c17876efee909929b1)) +- add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/ignaciojulio/Stellar-forge/issues/33)) ([5ba129f](https://github.com/ignaciojulio/Stellar-forge/commit/5ba129f8148add491d6dfd406138a3a3ab3a7f1c)) +- add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/ignaciojulio/Stellar-forge/issues/33)) ([9e76fc4](https://github.com/ignaciojulio/Stellar-forge/commit/9e76fc48a45c3512ffcc7e9c5edffae81dd0fdf6)) +- Add mainnet deployment checklist modal ([#35](https://github.com/ignaciojulio/Stellar-forge/issues/35)) ([d3e8f2d](https://github.com/ignaciojulio/Stellar-forge/commit/d3e8f2dfd04536bc5fede24ca84d1e0d416c8e39)) +- add MetadataAlreadySet guard in set_metadata ([ebbdd65](https://github.com/ignaciojulio/Stellar-forge/commit/ebbdd65360b829419d112b4dc8544c0396502a65)) +- add MintForm component with address validation and mintTokens service ([ac9df39](https://github.com/ignaciojulio/Stellar-forge/commit/ac9df395c2e4b4ad710f86211f0ee626e76238e0)) +- add network switching support ([#680](https://github.com/ignaciojulio/Stellar-forge/issues/680)) ([60e9f3f](https://github.com/ignaciojulio/Stellar-forge/commit/60e9f3fb185c5be0e93d0763c1ada5c6818ec3f3)) +- add OG tags, react-router-dom, clippy CI, and npm ci ([24d091c](https://github.com/ignaciojulio/Stellar-forge/commit/24d091c957c65e2b03eb374edfeb9f62c780d969)), closes [#54](https://github.com/ignaciojulio/Stellar-forge/issues/54) [#56](https://github.com/ignaciojulio/Stellar-forge/issues/56) [#68](https://github.com/ignaciojulio/Stellar-forge/issues/68) [#85](https://github.com/ignaciojulio/Stellar-forge/issues/85) +- add pause/unpause admin function to factory contract ([#39](https://github.com/ignaciojulio/Stellar-forge/issues/39)) ([5a5c965](https://github.com/ignaciojulio/Stellar-forge/commit/5a5c9657eb01f741a73fd68b07e8c129c0b72494)) +- add polling, last-updated indicator, and refresh to transaction history ([ac79943](https://github.com/ignaciojulio/Stellar-forge/commit/ac799436d088dc8a3876b6b1f8f1f3bda7e57e9e)), closes [#752](https://github.com/ignaciojulio/Stellar-forge/issues/752) +- add Prettier, fix all TS errors, add CI/CD pipeline, add formatAddress and Checkbox UI component ([a11180e](https://github.com/ignaciojulio/Stellar-forge/commit/a11180e10be6c60a668889a4ca85c4056e65db23)) +- add PWA support with vite-plugin-pwa ([#81](https://github.com/ignaciojulio/Stellar-forge/issues/81)) ([547110c](https://github.com/ignaciojulio/Stellar-forge/commit/547110c7a3bf0b9308433e6541a72851315dbc7f)) +- add reentrancy guard to create_token with Error::Reentrancy variant ([986de4b](https://github.com/ignaciojulio/Stellar-forge/commit/986de4be908dde9aca2df9497827bd4e57c72188)) +- add reusable Modal base component ([#527](https://github.com/ignaciojulio/Stellar-forge/issues/527)) ([e19c519](https://github.com/ignaciojulio/Stellar-forge/commit/e19c519d5362139603878ae605d798d0f32d4885)) +- add reusable Modal base component ([#527](https://github.com/ignaciojulio/Stellar-forge/issues/527)) ([f605b53](https://github.com/ignaciojulio/Stellar-forge/commit/f605b537b184538356ec3f5dfaf6e77a7023ec68)) +- add robots.txt, sitemap.xml, and meta description for SEO ([de6bb1c](https://github.com/ignaciojulio/Stellar-forge/commit/de6bb1ca190af7144dbcf42c4e375fb037629e40)) +- add robust useClipboard hook and refactor dashboard ([7149392](https://github.com/ignaciojulio/Stellar-forge/commit/7149392879177afb4890d27e84fcafd74993380c)), closes [#26](https://github.com/ignaciojulio/Stellar-forge/issues/26) +- add secure Admin Panel for factory fee management ([39e28a5](https://github.com/ignaciojulio/Stellar-forge/commit/39e28a5d8ea44f66da35c9103d0283f8ebbca68a)) +- Add security disclosure policy ([#47](https://github.com/ignaciojulio/Stellar-forge/issues/47)) ([096fcd7](https://github.com/ignaciojulio/Stellar-forge/commit/096fcd7db59170ab86e51293dfd1c261de5b856c)) +- Add Select UI component with accessibility and dark mode support ([412420a](https://github.com/ignaciojulio/Stellar-forge/commit/412420aaf6de26d11d299790904564aada4d9982)) +- add semantic release for automated versioning ([bcd42fe](https://github.com/ignaciojulio/Stellar-forge/commit/bcd42fe4045889bb25e4c751a1999444d91b9e48)) +- add sitemap generation script and update prebuild script to include it ([8948663](https://github.com/ignaciojulio/Stellar-forge/commit/89486632614de04d357937eebec497dfcd8656bc)) +- add skeleton loaders and a11y improvements ([#475](https://github.com/ignaciojulio/Stellar-forge/issues/475), [#477](https://github.com/ignaciojulio/Stellar-forge/issues/477)) ([1ea1e54](https://github.com/ignaciojulio/Stellar-forge/commit/1ea1e54760f52c844e342691ade1968f9d9f3db4)) +- add skeleton loaders for TokenExplorer and Dashboard ([42867fe](https://github.com/ignaciojulio/Stellar-forge/commit/42867fe60d0626302ff16fe9f97da65e7ca44aa9)), closes [#735](https://github.com/ignaciojulio/Stellar-forge/issues/735) +- add skeleton-loaders spec (requirements, design, tasks) ([ec3a9ed](https://github.com/ignaciojulio/Stellar-forge/commit/ec3a9edccdea9cb861af1c086b32f0e45188e011)) +- add social sharing for newly created tokens ([#521](https://github.com/ignaciojulio/Stellar-forge/issues/521)) ([7e2cdcc](https://github.com/ignaciojulio/Stellar-forge/commit/7e2cdcc311980edab824795b7afb3fa37f5bf470)) +- add Soroban benchmark harness for resource cost tracking ([#968](https://github.com/ignaciojulio/Stellar-forge/issues/968)) ([91b504f](https://github.com/ignaciojulio/Stellar-forge/commit/91b504f5f459c5e5491cf181a30c00c4611bfb1d)), closes [#12](https://github.com/ignaciojulio/Stellar-forge/issues/12) +- add soroban-token-sdk audit spec ([ae3686a](https://github.com/ignaciojulio/Stellar-forge/commit/ae3686a6aa6a9ea90c65cdac09212cbc17484e50)) +- add stellar contract optimize to deployment workflow ([4a56338](https://github.com/ignaciojulio/Stellar-forge/commit/4a5633820d68a264160311da5c161e36fa3dec9d)) +- add stellarExplorerUrl utility and wire explorer links ([d043699](https://github.com/ignaciojulio/Stellar-forge/commit/d04369980cab1a6f5a29c557b4857fdec90d0b43)) +- add Storybook stories for ConfirmModal, ProgressIndicator, and InsufficientBalanceWarning ([a25343e](https://github.com/ignaciojulio/Stellar-forge/commit/a25343ef58f82389e1ee34d6e81304cf0bcba9c8)) +- add Storybook with stories for all UI components ([564a5b8](https://github.com/ignaciojulio/Stellar-forge/commit/564a5b8747b18cecec42b800a28dd3b4845a51e6)) +- add Terms of Service acceptance modal before first transaction ([#529](https://github.com/ignaciojulio/Stellar-forge/issues/529)) ([53a7bc8](https://github.com/ignaciojulio/Stellar-forge/commit/53a7bc8473d5bfc7ddc0b4c8bb6b34d28c6f0b10)) +- add Terms of Service acceptance modal before first transaction ([#529](https://github.com/ignaciojulio/Stellar-forge/issues/529)) ([b2ddf76](https://github.com/ignaciojulio/Stellar-forge/commit/b2ddf76f997e7098519c2db85ef732176cc34ecf)) +- add testnet faucet integration via Friendbot ([#519](https://github.com/ignaciojulio/Stellar-forge/issues/519)) ([f7c2965](https://github.com/ignaciojulio/Stellar-forge/commit/f7c29653018bc9422437a517de60b021c9d9fd94)) +- add token event history with pagination and event details display ([9196fdf](https://github.com/ignaciojulio/Stellar-forge/commit/9196fdfa879502ba361811ad750a45319afee0e4)) +- add token search, filter, and sort to Dashboard ([a17250a](https://github.com/ignaciojulio/Stellar-forge/commit/a17250a7e7415c736f7abfb26c24ad63cce35e51)) +- add token search, filter, and sort to dashboard ([#64](https://github.com/ignaciojulio/Stellar-forge/issues/64)) ([eb80749](https://github.com/ignaciojulio/Stellar-forge/commit/eb80749f6deacb0dab54ba40af95e1d1693cdb81)) +- add TokenDashboard with pagination, search, and Explorer links ([d7ce574](https://github.com/ignaciojulio/Stellar-forge/commit/d7ce574bcb1e0b4670e1cc9c2d895946776aaf1a)) +- add TokenExplorer component with search and pagination ([4b21179](https://github.com/ignaciojulio/Stellar-forge/commit/4b211798c41fbfb492613f48e66a6bb174a37da1)) +- add TokenMetadata display component ([658efc0](https://github.com/ignaciojulio/Stellar-forge/commit/658efc0c1321a6b4794c0682e75894e0a45e66aa)) +- Add transaction retry logic with exponential backoff ([#62](https://github.com/ignaciojulio/Stellar-forge/issues/62)) ([f0d8f02](https://github.com/ignaciojulio/Stellar-forge/commit/f0d8f02c2d45a8649b21ef2a83f69fc757033bba)) +- Add TransactionHistory component and useTransactionHistory hook for Stellar token operations ([f8fed91](https://github.com/ignaciojulio/Stellar-forge/commit/f8fed914347008992fae259b506952c2d0c7ae88)) +- Add TransactionStatus component and tests ([4637fb8](https://github.com/ignaciojulio/Stellar-forge/commit/4637fb8c495482a5609f2f90ea6a5309aa09dd57)) +- add transfer_admin function with tests ([347d54f](https://github.com/ignaciojulio/Stellar-forge/commit/347d54fbbf885985964f991d51ed4c6807dcd071)) +- add TTL management for all Soroban storage writes ([7b34532](https://github.com/ignaciojulio/Stellar-forge/commit/7b3453265f83cbc0fe7f0dcaf8a736f21902887c)) +- add UI barrel export and update all imports ([2e4fbe0](https://github.com/ignaciojulio/Stellar-forge/commit/2e4fbe0e006564fee5c51396ba9137e9de42793c)) +- add update_admin function to token factory contract ([#479](https://github.com/ignaciojulio/Stellar-forge/issues/479)) ([5db1fe4](https://github.com/ignaciojulio/Stellar-forge/commit/5db1fe4734dc41788232efd3e11397bf74bd2954)) +- add useDebounce hook, apply to MintForm/BurnForm/Dashboard, fix build ([e8727e1](https://github.com/ignaciojulio/Stellar-forge/commit/e8727e16b4f1c50beca6977389720fe1497b192b)) +- add useFactoryState hook, coverage thresholds, and CI workflow ([15b366d](https://github.com/ignaciojulio/Stellar-forge/commit/15b366d315366e901a05351e7d200da9330bd39d)) +- Add useLocalStorage hook and tests ([56eac71](https://github.com/ignaciojulio/Stellar-forge/commit/56eac719547fd75bdd916da05ab5a8bcde6fc663)) +- add useTokenBalance hook and fix TypeScript errors ([43792b7](https://github.com/ignaciojulio/Stellar-forge/commit/43792b7593c29fff7929ca1c52e9096b32c4e3ef)) +- add useTokens pagination and useTokenInfo hook ([a473194](https://github.com/ignaciojulio/Stellar-forge/commit/a473194fbf697aa6feeed853de1253c30d8947df)) +- add VITE_TOKEN_WASM_HASH to env validation and fix duplicate import ([b027cc2](https://github.com/ignaciojulio/Stellar-forge/commit/b027cc256bc2c3381cedcfab7b48a81805e7f41f)) +- add wallet token portfolio dashboard ([cc28ab9](https://github.com/ignaciojulio/Stellar-forge/commit/cc28ab9f2d9505077bfbc430aac870983c6979f7)) +- add WalletButton UI component and integrate into App.tsx header ([cf20f69](https://github.com/ignaciojulio/Stellar-forge/commit/cf20f695cb93d60d96fa4f5f1592f1395ac2ef4f)) +- add wasm-opt post-processing for contract binary ([de1f779](https://github.com/ignaciojulio/Stellar-forge/commit/de1f779897d4ddbc938d9d1d58e1020d352081a0)) +- add whitelist for fee-free token creation ([59c0f59](https://github.com/ignaciojulio/Stellar-forge/commit/59c0f598ecfd74fa1cfe5a036a8ac22418e0d823)) +- **api:** add off-chain contract event indexer ([#943](https://github.com/ignaciojulio/Stellar-forge/issues/943)) ([19a9544](https://github.com/ignaciojulio/Stellar-forge/commit/19a9544f64827539f6c763c7f9c5b0df725b3cf0)) +- **api:** persist contract events in the indexer store (supersedes [#1138](https://github.com/ignaciojulio/Stellar-forge/issues/1138)) ([#1154](https://github.com/ignaciojulio/Stellar-forge/issues/1154)) ([45ad5bc](https://github.com/ignaciojulio/Stellar-forge/commit/45ad5bc0af5d6a8079746f03ff2399fc47be653b)) +- build token creation form UI on home page ([#667](https://github.com/ignaciojulio/Stellar-forge/issues/667)) ([0311381](https://github.com/ignaciojulio/Stellar-forge/commit/03113810e45d1c622661e7b3e6a9d19222d302a1)) +- Burn Tokens UI with danger-zone styling and safety confirmation ([#675](https://github.com/ignaciojulio/Stellar-forge/issues/675)) ([f894e11](https://github.com/ignaciojulio/Stellar-forge/commit/f894e116c013786ca1ddd4bce9a7af607a96c418)) +- **burn:** add data-testid attributes for balance display, Max button, and validation error ([0c72f14](https://github.com/ignaciojulio/Stellar-forge/commit/0c72f141647c5c6b77faca6fbd4ea22c696d4b5e)), closes [#755](https://github.com/ignaciojulio/Stellar-forge/issues/755) [#755](https://github.com/ignaciojulio/Stellar-forge/issues/755) +- **ci:** add access-control documentation drift check ([#1112](https://github.com/ignaciojulio/Stellar-forge/issues/1112)) ([#1148](https://github.com/ignaciojulio/Stellar-forge/issues/1148)) ([7b41cfd](https://github.com/ignaciojulio/Stellar-forge/commit/7b41cfda11bb62a91fc6bbcfbfd5bf3063f69f9f)) +- **ci:** add reproducible WASM hash verification workflow for mainnet deployments ([#950](https://github.com/ignaciojulio/Stellar-forge/issues/950)) ([abcdbce](https://github.com/ignaciojulio/Stellar-forge/commit/abcdbceaf28f24c23aaa963bf69c9a0b27b47fd5)), closes [#940](https://github.com/ignaciojulio/Stellar-forge/issues/940) +- comprehensive contract tests + fix lib.rs compilation errors ([#677](https://github.com/ignaciojulio/Stellar-forge/issues/677)) ([83a8f8f](https://github.com/ignaciojulio/Stellar-forge/commit/83a8f8f55ddbdd49046ce8ddb84be53360e16699)) +- **contract:** add batch token creation ([#487](https://github.com/ignaciojulio/Stellar-forge/issues/487)) ([b50b182](https://github.com/ignaciojulio/Stellar-forge/commit/b50b18207842a21052d69f1a85c67f893e36231a)) +- **contract:** add optional max supply cap to tokens ([#483](https://github.com/ignaciojulio/Stellar-forge/issues/483)) ([dc00eb6](https://github.com/ignaciojulio/Stellar-forge/commit/dc00eb6f44e00cdc437c4824c474cb227837dfef)) +- **contract:** add treasury fee split mechanism ([#485](https://github.com/ignaciojulio/Stellar-forge/issues/485)) ([d933acf](https://github.com/ignaciojulio/Stellar-forge/commit/d933acfc8876eb3f0db155a0ec7149d04bc2b323)) +- **contract:** emit events for all state-changing functions ([#482](https://github.com/ignaciojulio/Stellar-forge/issues/482)) ([0a375a8](https://github.com/ignaciojulio/Stellar-forge/commit/0a375a8a115d2c580d2c1e801e6936102eba4d19)) +- **contracts:** add schema versioning and implement migrate ([7293485](https://github.com/ignaciojulio/Stellar-forge/commit/7293485078366ff93f43ebb358360ad335dbde12)) +- **contracts:** add schema versioning and implement migrate ([a9fbd2e](https://github.com/ignaciojulio/Stellar-forge/commit/a9fbd2e525ce9f459d28cfdbc126c3a50ab68919)) +- create WalletConnectButton component ([766c6b9](https://github.com/ignaciojulio/Stellar-forge/commit/766c6b92eb995d711458cf20585591120ced5d91)) +- enable TypeScript strict mode ([#531](https://github.com/ignaciojulio/Stellar-forge/issues/531)) ([bb3ad84](https://github.com/ignaciojulio/Stellar-forge/commit/bb3ad84b61317ddca30bc365f9eb93d4bfc76b28)) +- enforce u128 for initial_supply and add InvalidTokenParams validation [#517](https://github.com/ignaciojulio/Stellar-forge/issues/517) ([67582a3](https://github.com/ignaciojulio/Stellar-forge/commit/67582a37491bb016ab44a09f6539321b776a29d0)) +- enhance security, add contract upgrade support, and integrate E2E tests into CI ([5695ca0](https://github.com/ignaciojulio/Stellar-forge/commit/5695ca0f03c7e7473d50b32cc8be6ca7c41ea560)) +- enhance token factory with DataKey enum and update storage access ([e0c24c0](https://github.com/ignaciojulio/Stellar-forge/commit/e0c24c04b0f0a9c6b9ea74afd0778915d2256a6f)) +- **explorer:** add Stellar Expert deep links for accounts, transactions, and contracts ([6d509a4](https://github.com/ignaciojulio/Stellar-forge/commit/6d509a4719802c15ba7a25454bd1cb63e51f4fdc)) +- extract contract error mapping to contractErrors.ts ([0420e56](https://github.com/ignaciojulio/Stellar-forge/commit/0420e56d1fa61c2f6923fd51f34e199f9d0aa058)) +- **factory:** add offset/limit pagination to get_tokens_by_creator ([#729](https://github.com/ignaciojulio/Stellar-forge/issues/729)) ([3f88aae](https://github.com/ignaciojulio/Stellar-forge/commit/3f88aaeb44917ccbcc07bfa5bb6c8fa8c69f1bec)) +- **frontend:** add ipfs gateway URL resolver and stabilize frontend checks ([005ff3f](https://github.com/ignaciojulio/Stellar-forge/commit/005ff3f36d8e792c1aae283a908f8e34f4540440)) +- **frontend:** block writes on network mismatch in metadata + admin forms ([#906](https://github.com/ignaciojulio/Stellar-forge/issues/906)) ([f6e88f3](https://github.com/ignaciojulio/Stellar-forge/commit/f6e88f390e3f87e5abd34ce35989c5907b83bd98)) +- **frontend:** implement i18n support with es and pt translations ([dcbc1b2](https://github.com/ignaciojulio/Stellar-forge/commit/dcbc1b2838650f7d285d92ffec61a226f0dd28df)) +- **frontend:** implement paginated global token listing (getAllTokens) ([#1028](https://github.com/ignaciojulio/Stellar-forge/issues/1028)) ([0e1b51e](https://github.com/ignaciojulio/Stellar-forge/commit/0e1b51e2590b3c23468f893f13e77e5f2eeb592a)), closes [#1017](https://github.com/ignaciojulio/Stellar-forge/issues/1017) +- **frontend:** verify deployed token WASM hash against factory state ([#986](https://github.com/ignaciojulio/Stellar-forge/issues/986)) ([6d1566a](https://github.com/ignaciojulio/Stellar-forge/commit/6d1566a8416e1ac44860fbb6a1395e062548141a)), closes [#925](https://github.com/ignaciojulio/Stellar-forge/issues/925) [hi#severity](https://github.com/hi/issues/severity) [#982](https://github.com/ignaciojulio/Stellar-forge/issues/982) [#984](https://github.com/ignaciojulio/Stellar-forge/issues/984) [#984](https://github.com/ignaciojulio/Stellar-forge/issues/984) [#984](https://github.com/ignaciojulio/Stellar-forge/issues/984) [#982](https://github.com/ignaciojulio/Stellar-forge/issues/982) +- **frontend:** wire network-mismatch banner + FAQ page, drop dead duplicate, fix repo URLs ([901021f](https://github.com/ignaciojulio/Stellar-forge/commit/901021f9ce8eac98d3d50bf5970006818bd835f8)) +- gate wallet and metadata actions behind ToS ([8318679](https://github.com/ignaciojulio/Stellar-forge/commit/8318679a05a77d2324ef1032e5a8735df50de38b)) +- global error boundary, toast system, and service error cleanup ([19dbf05](https://github.com/ignaciojulio/Stellar-forge/commit/19dbf055d8666ad6c29cfb08330d54dba1c37da2)) +- global error boundary, toast system, and service error cleanup ([6ca83ad](https://github.com/ignaciojulio/Stellar-forge/commit/6ca83ad43e48b722d1decf01505c7df900926b39)) +- **hooks:** add LRU eviction to useTokens module-level cache ([#967](https://github.com/ignaciojulio/Stellar-forge/issues/967)) ([25ca799](https://github.com/ignaciojulio/Stellar-forge/commit/25ca799e4b03c97a3d52752f7ccbdda0e0820816)) +- **hooks:** add useTransaction hook for transaction lifecycle ([#489](https://github.com/ignaciojulio/Stellar-forge/issues/489)) ([18debc3](https://github.com/ignaciojulio/Stellar-forge/commit/18debc33c6bc0dd55ebb830be061c32663b9b2bd)) +- implement BigInt-safe formatting utilities ([fc30b37](https://github.com/ignaciojulio/Stellar-forge/commit/fc30b3739e3829c47c164b5fc3ed766a720160e7)) +- implement burn_enabled per-token flag ([7d265e8](https://github.com/ignaciojulio/Stellar-forge/commit/7d265e844a3490af982d1665e0d6d17287a21ad1)) +- Implement Freighter Wallet Integration ([b91a66e](https://github.com/ignaciojulio/Stellar-forge/commit/b91a66ea7d8ca5e98b04da98c036bde9103896a8)) +- implement Freighter wallet integration ([#666](https://github.com/ignaciojulio/Stellar-forge/issues/666)) ([8416cfd](https://github.com/ignaciojulio/Stellar-forge/commit/8416cfd8dd76863b1142ec6662bd063a5eb5c2c8)) +- implement global error boundary ([#473](https://github.com/ignaciojulio/Stellar-forge/issues/473)) ([d83fe50](https://github.com/ignaciojulio/Stellar-forge/commit/d83fe50a891c8e6b0ddf9657f533068d85ae8d9d)) +- implement Horizon API retry logic with exponential backoff and Retry-After handling [#499](https://github.com/ignaciojulio/Stellar-forge/issues/499) ([cfd31b5](https://github.com/ignaciojulio/Stellar-forge/commit/cfd31b5b7d3cb95c5a4ac367ed93ec95da884a5f)) +- implement mobile-responsive design for all components ([cfdf285](https://github.com/ignaciojulio/Stellar-forge/commit/cfdf285acfd73648d3ddb9189c9603994e422016)) +- implement pagination for token dashboard ([#29](https://github.com/ignaciojulio/Stellar-forge/issues/29)) ([9aa41b1](https://github.com/ignaciojulio/Stellar-forge/commit/9aa41b1489fc9a4b07d3be68c6f2521197a402f0)) +- implement Pinata IPFS upload service with tests ([6b33365](https://github.com/ignaciojulio/Stellar-forge/commit/6b33365592b88e4835ff4b0728bfd33fe5c65504)) +- implement Pinata IPFS upload with progress tracking and error handling ([53b3684](https://github.com/ignaciojulio/Stellar-forge/commit/53b368444cefd75a4ab1ae0ad0856244b78d0d59)) +- implement responsive mobile layout (issue [#616](https://github.com/ignaciojulio/Stellar-forge/issues/616)) ([49ddf41](https://github.com/ignaciojulio/Stellar-forge/commit/49ddf41412597f035283a56ce005728838a7bf8e)) +- implement reusable CopyButton component with Clipboard API integration ([2f8b716](https://github.com/ignaciojulio/Stellar-forge/commit/2f8b71673d4bcfed75cea83aba41ba75c7d39d59)) +- implement Soroban contract invocation logic in StellarService ([3a4af37](https://github.com/ignaciojulio/Stellar-forge/commit/3a4af37b668bc7dd633dca8f80ab34230a160da8)) +- implement Soroban RPC interactions in stellar.ts ([42c9d18](https://github.com/ignaciojulio/Stellar-forge/commit/42c9d18240eccc884dcee88d0e56e1897fe2a7de)) +- implement StellarService with full Soroban RPC integration ([3f0a520](https://github.com/ignaciojulio/Stellar-forge/commit/3f0a52060e1264e34239d59ede6542c9a2791bf6)) +- implement token burn UI and service ([a199523](https://github.com/ignaciojulio/Stellar-forge/commit/a19952319a4e6efc77ccf128bd72ac0fe6fdc2e3)) +- implement Token Dashboard page ([#673](https://github.com/ignaciojulio/Stellar-forge/issues/673)) ([c3b204c](https://github.com/ignaciojulio/Stellar-forge/commit/c3b204c15fcca7827fd91c69f97cc0708395e3a8)) +- implement token detail page ([a79ef19](https://github.com/ignaciojulio/Stellar-forge/commit/a79ef19b62d87c742306511e4c6d4194f47f4301)) +- implement TokenDashboard page with TokenCard component and index-based pagination ([4af373b](https://github.com/ignaciojulio/Stellar-forge/commit/4af373b0d6ae3928d8c9f09f6fec2e181c1fd857)) +- implement TokenDetail page ([#470](https://github.com/ignaciojulio/Stellar-forge/issues/470)) ([71ca751](https://github.com/ignaciojulio/Stellar-forge/commit/71ca75186290f61636b5217b0e4817d8d70d5860)) +- implement TokenDetail page with IPFS metadata, mint/burn/set-metadata inline forms, and 404 state ([9c7f0eb](https://github.com/ignaciojulio/Stellar-forge/commit/9c7f0eb21f1218f5ad84e0026eb007b6760fcf49)) +- implement transaction status tracking ([#681](https://github.com/ignaciojulio/Stellar-forge/issues/681)) ([3c0a793](https://github.com/ignaciojulio/Stellar-forge/commit/3c0a79320128a7e0ebe31f2c6c2091dedbabc790)) +- implement update_treasury in token-factory ([0c381d3](https://github.com/ignaciojulio/Stellar-forge/commit/0c381d364fc58b048d6ac3b5a3c8e2fdb014a4d4)) +- implement useLocalStorage for dark mode context and add tests for useDarkMode hook ([f04664c](https://github.com/ignaciojulio/Stellar-forge/commit/f04664cf78bf2f23ca284ae6d8f7807432928a30)) +- implement useLocalStorage hook and integrate for Dark Mode, Network, and Language [#518](https://github.com/ignaciojulio/Stellar-forge/issues/518) ([9a25f84](https://github.com/ignaciojulio/Stellar-forge/commit/9a25f843fb0e4aa8c1cd12c84a1e045243386228)) +- implement useTokens hook with parallel fetching and cache ([d9cc12d](https://github.com/ignaciojulio/Stellar-forge/commit/d9cc12d47d2b1f03c90a062a7a4c43e5a8b9d16f)), closes [#16](https://github.com/ignaciojulio/Stellar-forge/issues/16) +- implement wallet auto-reconnect and Freighter event listeners ([4cba9dc](https://github.com/ignaciojulio/Stellar-forge/commit/4cba9dc763125c9a8fa920a14aa94eb91f241835)) +- integrate Sentry error tracking for failed contract calls ([e0cb9f9](https://github.com/ignaciojulio/Stellar-forge/commit/e0cb9f995c7d04606937ca8c1df0cd923e71c96d)), closes [#757](https://github.com/ignaciojulio/Stellar-forge/issues/757) +- **ipfs:** implement IPFS metadata upload via Pinata ([#669](https://github.com/ignaciojulio/Stellar-forge/issues/669)) ([949bcc3](https://github.com/ignaciojulio/Stellar-forge/commit/949bcc3dc44b247c9fc084edd83cac814a510dd2)) +- Mint Tokens UI with RHF validation and token dropdown ([#674](https://github.com/ignaciojulio/Stellar-forge/issues/674)) ([223235d](https://github.com/ignaciojulio/Stellar-forge/commit/223235d8b6d6995d04610e0103b44853d267c4f4)) +- mobile responsive design ([90814c2](https://github.com/ignaciojulio/Stellar-forge/commit/90814c291d43fc2cc5cb1082eaedb49d70b8f228)) +- **monitoring:** add monitoring docs and sentry dependency ([e043a5c](https://github.com/ignaciojulio/Stellar-forge/commit/e043a5c4778490cdc5f61a5a6a8bec84f04a97e0)) +- **monitoring:** add Sentry, uptime monitoring, and health endpoint ([cee6369](https://github.com/ignaciojulio/Stellar-forge/commit/cee6369984c5aa792f631cb2d99f5387f523a675)) +- move wallet state to global React Context ([6c24340](https://github.com/ignaciojulio/Stellar-forge/commit/6c243409493ecaf75dcaf7020b07e51fa764489e)) +- network switcher with mainnet warning and localStorage persistence ([5fa8531](https://github.com/ignaciojulio/Stellar-forge/commit/5fa8531fe7735ea781dfdcc3d0393e43b2392138)) +- pause/unpause factory already implemented; add burn-while-paused test ([#480](https://github.com/ignaciojulio/Stellar-forge/issues/480)) ([4dd54ca](https://github.com/ignaciojulio/Stellar-forge/commit/4dd54cae186d0f659b02c09174ef52b8c45d40bd)) +- provide services via StellarContext, re-init on network change ([4f924de](https://github.com/ignaciojulio/Stellar-forge/commit/4f924de5f21060928b716c73263e9dde08eb6232)) +- **security:** add Content Security Policy and security headers ([19f0f1f](https://github.com/ignaciojulio/Stellar-forge/commit/19f0f1f1a414ff3aaa40c7d880892ae53d0fb494)) +- **security:** add dependency audit and Dependabot configuration ([9f404c1](https://github.com/ignaciojulio/Stellar-forge/commit/9f404c125b296e2693acefd67f2e6c0c1476f987)), closes [hi#severity](https://github.com/hi/issues/severity) [#502](https://github.com/ignaciojulio/Stellar-forge/issues/502) +- **security:** add strict CSP, X-Frame-Options, and X-Content-Type-Options headers ([a625191](https://github.com/ignaciojulio/Stellar-forge/commit/a625191242ad136c2f085d1524916a0781bbc0ea)) +- **security:** add triage and waiver workflow for audit findings ([#981](https://github.com/ignaciojulio/Stellar-forge/issues/981)) ([aa0ceab](https://github.com/ignaciojulio/Stellar-forge/commit/aa0ceab6d134bb7706f4bdb03f4e591bc5eba1ee)), closes [hi#or-above](https://github.com/hi/issues/or-above) [#939](https://github.com/ignaciojulio/Stellar-forge/issues/939) +- show pre-signature fee recipient breakdown and batch total (Closes [#1108](https://github.com/ignaciojulio/Stellar-forge/issues/1108)) ([#1124](https://github.com/ignaciojulio/Stellar-forge/issues/1124)) ([f983539](https://github.com/ignaciojulio/Stellar-forge/commit/f983539afe0eccc35503bc0a0378e47f0f0d70de)) +- show XLM/USD equivalent in FeeDisplay component ([fd3c20d](https://github.com/ignaciojulio/Stellar-forge/commit/fd3c20d6172b5f12542e4822efc0e193e64b9f37)), closes [#733](https://github.com/ignaciojulio/Stellar-forge/issues/733) +- toast notification system already implemented ([#474](https://github.com/ignaciojulio/Stellar-forge/issues/474)) ([73b04c9](https://github.com/ignaciojulio/Stellar-forge/commit/73b04c93422a042df4c9343a024b0d799f062b65)) +- **token-factory:** validate create_token params and use InvalidParameters error ([4e7abc4](https://github.com/ignaciojulio/Stellar-forge/commit/4e7abc445ef9bb859033a1154087f4e06c60d426)) +- **ui:** add DropZone drag-and-drop component and replace file input in MetadataUploadForm ([fee9791](https://github.com/ignaciojulio/Stellar-forge/commit/fee979106b6aa2f6cabdae7a8d89e34187fb4516)) +- **ui:** add network-aware Stellar Expert explorer links ([20dced8](https://github.com/ignaciojulio/Stellar-forge/commit/20dced85535f61c3700295b38486148e21fcee85)), closes [#621](https://github.com/ignaciojulio/Stellar-forge/issues/621) +- **ui:** confirmation modal before every state-changing transaction ([#490](https://github.com/ignaciojulio/Stellar-forge/issues/490)) ([88291e3](https://github.com/ignaciojulio/Stellar-forge/commit/88291e3a54fb6581068f0aa474301effc8d5839f)) +- **ui:** implement MetadataForm with IPFS upload + Stellar linking ([#676](https://github.com/ignaciojulio/Stellar-forge/issues/676)) ([20f5327](https://github.com/ignaciojulio/Stellar-forge/commit/20f53270a24aafadba31984dde41b3b1f4605ad7)) +- upgrade mechanism, ADRs, QR code sharing, onboarding tutorial ([7b59535](https://github.com/ignaciojulio/Stellar-forge/commit/7b5953553e50e0d011aefd8d581d346cd03eef0d)), closes [#1](https://github.com/ignaciojulio/Stellar-forge/issues/1) [#2](https://github.com/ignaciojulio/Stellar-forge/issues/2) [#3](https://github.com/ignaciojulio/Stellar-forge/issues/3) [#4](https://github.com/ignaciojulio/Stellar-forge/issues/4) +- **ux:** insufficient balance warning before transaction submission ([#496](https://github.com/ignaciojulio/Stellar-forge/issues/496)) ([0777d93](https://github.com/ignaciojulio/Stellar-forge/commit/0777d937bf16c0428cc0c9b8981bcf6322cfba66)) +- wire setMetadata to StellarService in TokenDetail ([04de946](https://github.com/ignaciojulio/Stellar-forge/commit/04de946b9f1be0b11b385f12dd0138798cb79437)) +- wire up mint and burn token UI to contract ([ca6b7b4](https://github.com/ignaciojulio/Stellar-forge/commit/ca6b7b41537ff00ac62d56316089355f62a6b188)), closes [#541](https://github.com/ignaciojulio/Stellar-forge/issues/541) ### Performance Improvements -* apply useMemo, useCallback, and React.memo for render optimizations ([8afb78a](https://github.com/ignaciojulio/Stellar-forge/commit/8afb78ab2911e0681f21866959e39a6fbf41e427)) -* fetch creator token pages concurrently with capped concurrency ([#969](https://github.com/ignaciojulio/Stellar-forge/issues/969)) ([bfdc828](https://github.com/ignaciojulio/Stellar-forge/commit/bfdc8285861c5382f87933f48f45c85dfdc50c5d)), closes [#16](https://github.com/ignaciojulio/Stellar-forge/issues/16) -* **frontend:** implement route-level code splitting and lazy load stellar-sdk ([a9ed488](https://github.com/ignaciojulio/Stellar-forge/commit/a9ed488c4633a910765ae678de6f5cc63589a4e2)) -* **api:** correct Freighter SEP-53 signature verification in auth challenge ([#1169](https://github.com/Favourorg/Stellar-forge/issues/1169)) ([21cbed6](https://github.com/Favourorg/Stellar-forge/commit/21cbed64699d8eef3796f7e3d895e4ba93ef427a)) +- apply useMemo, useCallback, and React.memo for render optimizations ([8afb78a](https://github.com/ignaciojulio/Stellar-forge/commit/8afb78ab2911e0681f21866959e39a6fbf41e427)) +- fetch creator token pages concurrently with capped concurrency ([#969](https://github.com/ignaciojulio/Stellar-forge/issues/969)) ([bfdc828](https://github.com/ignaciojulio/Stellar-forge/commit/bfdc8285861c5382f87933f48f45c85dfdc50c5d)), closes [#16](https://github.com/ignaciojulio/Stellar-forge/issues/16) +- **frontend:** implement route-level code splitting and lazy load stellar-sdk ([a9ed488](https://github.com/ignaciojulio/Stellar-forge/commit/a9ed488c4633a910765ae678de6f5cc63589a4e2)) +- **api:** correct Freighter SEP-53 signature verification in auth challenge ([#1169](https://github.com/Favourorg/Stellar-forge/issues/1169)) ([21cbed6](https://github.com/Favourorg/Stellar-forge/commit/21cbed64699d8eef3796f7e3d895e4ba93ef427a)) # [1.8.0](https://github.com/Favourorg/Stellar-forge/compare/v1.7.0...v1.8.0) (2026-08-24) - ### Features -* add client-side CID verification for metadata integrity ([#1139](https://github.com/Favourorg/Stellar-forge/issues/1139)) ([82e9a1b](https://github.com/Favourorg/Stellar-forge/commit/82e9a1b72bf1c78efede6522669d40707a5f295c)) +- add client-side CID verification for metadata integrity ([#1139](https://github.com/Favourorg/Stellar-forge/issues/1139)) ([82e9a1b](https://github.com/Favourorg/Stellar-forge/commit/82e9a1b72bf1c78efede6522669d40707a5f295c)) # [1.7.0](https://github.com/Favourorg/Stellar-forge/compare/v1.6.0...v1.7.0) (2026-08-24) - ### Features -* **api:** persist contract events in the indexer store (supersedes [#1138](https://github.com/Favourorg/Stellar-forge/issues/1138)) ([#1154](https://github.com/Favourorg/Stellar-forge/issues/1154)) ([45ad5bc](https://github.com/Favourorg/Stellar-forge/commit/45ad5bc0af5d6a8079746f03ff2399fc47be653b)) +- **api:** persist contract events in the indexer store (supersedes [#1138](https://github.com/Favourorg/Stellar-forge/issues/1138)) ([#1154](https://github.com/Favourorg/Stellar-forge/issues/1154)) ([45ad5bc](https://github.com/Favourorg/Stellar-forge/commit/45ad5bc0af5d6a8079746f03ff2399fc47be653b)) # [1.6.0](https://github.com/Favourorg/Stellar-forge/compare/v1.5.11...v1.6.0) (2026-08-24) - ### Features -* **ci:** add access-control documentation drift check ([#1112](https://github.com/Favourorg/Stellar-forge/issues/1112)) ([#1148](https://github.com/Favourorg/Stellar-forge/issues/1148)) ([7b41cfd](https://github.com/Favourorg/Stellar-forge/commit/7b41cfda11bb62a91fc6bbcfbfd5bf3063f69f9f)) +- **ci:** add access-control documentation drift check ([#1112](https://github.com/Favourorg/Stellar-forge/issues/1112)) ([#1148](https://github.com/Favourorg/Stellar-forge/issues/1148)) ([7b41cfd](https://github.com/Favourorg/Stellar-forge/commit/7b41cfda11bb62a91fc6bbcfbfd5bf3063f69f9f)) ## [1.5.11](https://github.com/Favourorg/Stellar-forge/compare/v1.5.10...v1.5.11) (2026-08-24) - ### Bug Fixes -* reclaim orphaned IPFS pins on failed set_metadata (Closes [#1096](https://github.com/Favourorg/Stellar-forge/issues/1096)) ([#1146](https://github.com/Favourorg/Stellar-forge/issues/1146)) ([d845880](https://github.com/Favourorg/Stellar-forge/commit/d84588094a620097ffcb3d66135201ffedc70ad8)) +- reclaim orphaned IPFS pins on failed set_metadata (Closes [#1096](https://github.com/Favourorg/Stellar-forge/issues/1096)) ([#1146](https://github.com/Favourorg/Stellar-forge/issues/1146)) ([d845880](https://github.com/Favourorg/Stellar-forge/commit/d84588094a620097ffcb3d66135201ffedc70ad8)) ## [1.5.10](https://github.com/Favourorg/Stellar-forge/compare/v1.5.9...v1.5.10) (2026-08-24) - ### Bug Fixes -* **api:** add rate limiting to auth challenge endpoints ([#1144](https://github.com/Favourorg/Stellar-forge/issues/1144)) ([600e8a0](https://github.com/Favourorg/Stellar-forge/commit/600e8a057f98129ad93a520030c3224682da0400)), closes [#1101](https://github.com/Favourorg/Stellar-forge/issues/1101) -* **api:** sanitize lastError in health/indexer to avoid leaking internal error details ([#1143](https://github.com/Favourorg/Stellar-forge/issues/1143)) ([c51d179](https://github.com/Favourorg/Stellar-forge/commit/c51d179b782507f167150b719309715fcf6225d9)), closes [#1103](https://github.com/Favourorg/Stellar-forge/issues/1103) +- **api:** add rate limiting to auth challenge endpoints ([#1144](https://github.com/Favourorg/Stellar-forge/issues/1144)) ([600e8a0](https://github.com/Favourorg/Stellar-forge/commit/600e8a057f98129ad93a520030c3224682da0400)), closes [#1101](https://github.com/Favourorg/Stellar-forge/issues/1101) +- **api:** sanitize lastError in health/indexer to avoid leaking internal error details ([#1143](https://github.com/Favourorg/Stellar-forge/issues/1143)) ([c51d179](https://github.com/Favourorg/Stellar-forge/commit/c51d179b782507f167150b719309715fcf6225d9)), closes [#1103](https://github.com/Favourorg/Stellar-forge/issues/1103) ## [1.5.9](https://github.com/Favourorg/Stellar-forge/compare/v1.5.8...v1.5.9) (2026-08-24) - ### Bug Fixes -* **contracts:** fuzz the real burn entrypoint, not a reimplementation ([#1098](https://github.com/Favourorg/Stellar-forge/issues/1098)) ([#1137](https://github.com/Favourorg/Stellar-forge/issues/1137)) ([be8a342](https://github.com/Favourorg/Stellar-forge/commit/be8a3424d514423f9946635ff899440911bd3377)) +- **contracts:** fuzz the real burn entrypoint, not a reimplementation ([#1098](https://github.com/Favourorg/Stellar-forge/issues/1098)) ([#1137](https://github.com/Favourorg/Stellar-forge/issues/1137)) ([be8a342](https://github.com/Favourorg/Stellar-forge/commit/be8a3424d514423f9946635ff899440911bd3377)) ## [1.5.8](https://github.com/Favourorg/Stellar-forge/compare/v1.5.7...v1.5.8) (2026-08-24) - ### Bug Fixes -* isolate per-recipient fee-split transfer failures from aborting the call ([#1136](https://github.com/Favourorg/Stellar-forge/issues/1136)) ([6e68f0d](https://github.com/Favourorg/Stellar-forge/commit/6e68f0d78f1272fa6a31cc6d8cb54859dc9fb83b)) +- isolate per-recipient fee-split transfer failures from aborting the call ([#1136](https://github.com/Favourorg/Stellar-forge/issues/1136)) ([6e68f0d](https://github.com/Favourorg/Stellar-forge/commit/6e68f0d78f1272fa6a31cc6d8cb54859dc9fb83b)) ## [1.5.7](https://github.com/Favourorg/Stellar-forge/compare/v1.5.6...v1.5.7) (2026-08-24) - ### Bug Fixes -* **contracts:** enforce MAX_BATCH_SIZE cap in create_tokens_batch (Closes [#1100](https://github.com/Favourorg/Stellar-forge/issues/1100)) ([#1135](https://github.com/Favourorg/Stellar-forge/issues/1135)) ([2ba33e5](https://github.com/Favourorg/Stellar-forge/commit/2ba33e5e5516b2e3e66388ebd3dcb4568a3b5a14)) +- **contracts:** enforce MAX_BATCH_SIZE cap in create_tokens_batch (Closes [#1100](https://github.com/Favourorg/Stellar-forge/issues/1100)) ([#1135](https://github.com/Favourorg/Stellar-forge/issues/1135)) ([2ba33e5](https://github.com/Favourorg/Stellar-forge/commit/2ba33e5e5516b2e3e66388ebd3dcb4568a3b5a14)) ## [1.5.6](https://github.com/Favourorg/Stellar-forge/compare/v1.5.5...v1.5.6) (2026-08-24) - ### Bug Fixes -* **infra:** consolidate vercel.json security headers (Closes [#1104](https://github.com/Favourorg/Stellar-forge/issues/1104)) ([#1134](https://github.com/Favourorg/Stellar-forge/issues/1134)) ([fc64bea](https://github.com/Favourorg/Stellar-forge/commit/fc64bea1d5185c43fe289214857246bfe014e51c)) +- **infra:** consolidate vercel.json security headers (Closes [#1104](https://github.com/Favourorg/Stellar-forge/issues/1104)) ([#1134](https://github.com/Favourorg/Stellar-forge/issues/1134)) ([fc64bea](https://github.com/Favourorg/Stellar-forge/commit/fc64bea1d5185c43fe289214857246bfe014e51c)) ## [1.5.5](https://github.com/Favourorg/Stellar-forge/compare/v1.5.4...v1.5.5) (2026-08-22) - ### Bug Fixes -* **api:** store wallet-auth challenges in Vercel KV (Closes [#1091](https://github.com/Favourorg/Stellar-forge/issues/1091)) ([#1132](https://github.com/Favourorg/Stellar-forge/issues/1132)) ([62941bb](https://github.com/Favourorg/Stellar-forge/commit/62941bb0131970c10fc56f5fcf19135eefe8de3f)) +- **api:** store wallet-auth challenges in Vercel KV (Closes [#1091](https://github.com/Favourorg/Stellar-forge/issues/1091)) ([#1132](https://github.com/Favourorg/Stellar-forge/issues/1132)) ([62941bb](https://github.com/Favourorg/Stellar-forge/commit/62941bb0131970c10fc56f5fcf19135eefe8de3f)) ## [1.5.4](https://github.com/Favourorg/Stellar-forge/compare/v1.5.3...v1.5.4) (2026-08-22) - ### Bug Fixes -* **infra:** schedule the indexer cron in vercel.json (Closes [#1090](https://github.com/Favourorg/Stellar-forge/issues/1090)) ([#1130](https://github.com/Favourorg/Stellar-forge/issues/1130)) ([288d5f3](https://github.com/Favourorg/Stellar-forge/commit/288d5f3b1208405fd08e12342fef2ae58cf25a7b)), closes [#1123](https://github.com/Favourorg/Stellar-forge/issues/1123) [#1124](https://github.com/Favourorg/Stellar-forge/issues/1124) [#1125](https://github.com/Favourorg/Stellar-forge/issues/1125) [#1126](https://github.com/Favourorg/Stellar-forge/issues/1126) [#1126](https://github.com/Favourorg/Stellar-forge/issues/1126) [#1126](https://github.com/Favourorg/Stellar-forge/issues/1126) [#1121](https://github.com/Favourorg/Stellar-forge/issues/1121) [#1121](https://github.com/Favourorg/Stellar-forge/issues/1121) +- **infra:** schedule the indexer cron in vercel.json (Closes [#1090](https://github.com/Favourorg/Stellar-forge/issues/1090)) ([#1130](https://github.com/Favourorg/Stellar-forge/issues/1130)) ([288d5f3](https://github.com/Favourorg/Stellar-forge/commit/288d5f3b1208405fd08e12342fef2ae58cf25a7b)), closes [#1123](https://github.com/Favourorg/Stellar-forge/issues/1123) [#1124](https://github.com/Favourorg/Stellar-forge/issues/1124) [#1125](https://github.com/Favourorg/Stellar-forge/issues/1125) [#1126](https://github.com/Favourorg/Stellar-forge/issues/1126) [#1126](https://github.com/Favourorg/Stellar-forge/issues/1126) [#1126](https://github.com/Favourorg/Stellar-forge/issues/1126) [#1121](https://github.com/Favourorg/Stellar-forge/issues/1121) [#1121](https://github.com/Favourorg/Stellar-forge/issues/1121) ## [1.5.3](https://github.com/Favourorg/Stellar-forge/compare/v1.5.2...v1.5.3) (2026-08-22) - ### Bug Fixes -* **api:** remove clientIp() dead code with inverted XFF parsing (audit [#26](https://github.com/Favourorg/Stellar-forge/issues/26)) ([#1129](https://github.com/Favourorg/Stellar-forge/issues/1129)) ([fa1a888](https://github.com/Favourorg/Stellar-forge/commit/fa1a888c99133d2fafab52f3e79444d1ac188766)), closes [#1101](https://github.com/Favourorg/Stellar-forge/issues/1101) +- **api:** remove clientIp() dead code with inverted XFF parsing (audit [#26](https://github.com/Favourorg/Stellar-forge/issues/26)) ([#1129](https://github.com/Favourorg/Stellar-forge/issues/1129)) ([fa1a888](https://github.com/Favourorg/Stellar-forge/commit/fa1a888c99133d2fafab52f3e79444d1ac188766)), closes [#1101](https://github.com/Favourorg/Stellar-forge/issues/1101) ## [1.5.2](https://github.com/Favourorg/Stellar-forge/compare/v1.5.1...v1.5.2) (2026-08-22) - ### Bug Fixes -* **explorer:** snapshot tokenCount once per session to prevent pagination drift ([#1126](https://github.com/Favourorg/Stellar-forge/issues/1126)) ([a27f77b](https://github.com/Favourorg/Stellar-forge/commit/a27f77b8dda5b76feced0cf6baeac7a42a84bcf0)) +- **explorer:** snapshot tokenCount once per session to prevent pagination drift ([#1126](https://github.com/Favourorg/Stellar-forge/issues/1126)) ([a27f77b](https://github.com/Favourorg/Stellar-forge/commit/a27f77b8dda5b76feced0cf6baeac7a42a84bcf0)) ## [1.5.1](https://github.com/Favourorg/Stellar-forge/compare/v1.5.0...v1.5.1) (2026-08-22) - ### Bug Fixes -* align frontend token validation with contract (name ≤ 32 UTF-8 bytes, remove ASCII-only restriction) ([#1125](https://github.com/Favourorg/Stellar-forge/issues/1125)) ([cefa9b9](https://github.com/Favourorg/Stellar-forge/commit/cefa9b9c13bbc7f2b5a770e5376369c4875c3833)) +- align frontend token validation with contract (name ≤ 32 UTF-8 bytes, remove ASCII-only restriction) ([#1125](https://github.com/Favourorg/Stellar-forge/issues/1125)) ([cefa9b9](https://github.com/Favourorg/Stellar-forge/commit/cefa9b9c13bbc7f2b5a770e5376369c4875c3833)) # [1.5.0](https://github.com/Favourorg/Stellar-forge/compare/v1.4.4...v1.5.0) (2026-08-22) - ### Features -* show pre-signature fee recipient breakdown and batch total (Closes [#1108](https://github.com/Favourorg/Stellar-forge/issues/1108)) ([#1124](https://github.com/Favourorg/Stellar-forge/issues/1124)) ([f983539](https://github.com/Favourorg/Stellar-forge/commit/f983539afe0eccc35503bc0a0378e47f0f0d70de)) +- show pre-signature fee recipient breakdown and batch total (Closes [#1108](https://github.com/Favourorg/Stellar-forge/issues/1108)) ([#1124](https://github.com/Favourorg/Stellar-forge/issues/1124)) ([f983539](https://github.com/Favourorg/Stellar-forge/commit/f983539afe0eccc35503bc0a0378e47f0f0d70de)) ## [1.4.4](https://github.com/Favourorg/Stellar-forge/compare/v1.4.3...v1.4.4) (2026-08-22) - ### Bug Fixes -* remove 'unsafe-inline' from CSP style-src (Closes [#1105](https://github.com/Favourorg/Stellar-forge/issues/1105)) ([#1123](https://github.com/Favourorg/Stellar-forge/issues/1123)) ([838129c](https://github.com/Favourorg/Stellar-forge/commit/838129ccc63f862350ac86ee1efcc1ba2ae4a163)) +- remove 'unsafe-inline' from CSP style-src (Closes [#1105](https://github.com/Favourorg/Stellar-forge/issues/1105)) ([#1123](https://github.com/Favourorg/Stellar-forge/issues/1123)) ([838129c](https://github.com/Favourorg/Stellar-forge/commit/838129ccc63f862350ac86ee1efcc1ba2ae4a163)) ## [1.4.3](https://github.com/Favourorg/Stellar-forge/compare/v1.4.2...v1.4.3) (2026-08-22) - ### Bug Fixes -* **specs:** resolve spec stubs and enforce kiro spec documentation ([#1117](https://github.com/Favourorg/Stellar-forge/issues/1117)) ([#1120](https://github.com/Favourorg/Stellar-forge/issues/1120)) ([0875cd2](https://github.com/Favourorg/Stellar-forge/commit/0875cd23e96ae0bb87a7d897418349aaa04b18d8)), closes [#1099](https://github.com/Favourorg/Stellar-forge/issues/1099) [#1107](https://github.com/Favourorg/Stellar-forge/issues/1107) [#1108](https://github.com/Favourorg/Stellar-forge/issues/1108) [#1113](https://github.com/Favourorg/Stellar-forge/issues/1113) [#1118](https://github.com/Favourorg/Stellar-forge/issues/1118) +- **specs:** resolve spec stubs and enforce kiro spec documentation ([#1117](https://github.com/Favourorg/Stellar-forge/issues/1117)) ([#1120](https://github.com/Favourorg/Stellar-forge/issues/1120)) ([0875cd2](https://github.com/Favourorg/Stellar-forge/commit/0875cd23e96ae0bb87a7d897418349aaa04b18d8)), closes [#1099](https://github.com/Favourorg/Stellar-forge/issues/1099) [#1107](https://github.com/Favourorg/Stellar-forge/issues/1107) [#1108](https://github.com/Favourorg/Stellar-forge/issues/1108) [#1113](https://github.com/Favourorg/Stellar-forge/issues/1113) [#1118](https://github.com/Favourorg/Stellar-forge/issues/1118) ## [1.4.2](https://github.com/Favourorg/Stellar-forge/compare/v1.4.1...v1.4.2) (2026-08-20) - ### Bug Fixes -* relabel TokenDetail Admin field to 'Deployed by' (Closes [#1109](https://github.com/Favourorg/Stellar-forge/issues/1109)) ([#1119](https://github.com/Favourorg/Stellar-forge/issues/1119)) ([5d5df07](https://github.com/Favourorg/Stellar-forge/commit/5d5df075612a6e510448e17087c281d987a36478)) +- relabel TokenDetail Admin field to 'Deployed by' (Closes [#1109](https://github.com/Favourorg/Stellar-forge/issues/1109)) ([#1119](https://github.com/Favourorg/Stellar-forge/issues/1119)) ([5d5df07](https://github.com/Favourorg/Stellar-forge/commit/5d5df075612a6e510448e17087c281d987a36478)) ## [1.4.1](https://github.com/Favourorg/Stellar-forge/compare/v1.4.0...v1.4.1) (2026-08-03) - ### Bug Fixes -* **build:** build the contract for wasm32v1-none everywhere ([#940](https://github.com/Favourorg/Stellar-forge/issues/940)) ([0aa6df3](https://github.com/Favourorg/Stellar-forge/commit/0aa6df38bc25e5bf1941a7dbbafd12616a108505)) -* **security:** stop shipping Pinata credentials in the frontend bundle ([#921](https://github.com/Favourorg/Stellar-forge/issues/921)) ([2a23cad](https://github.com/Favourorg/Stellar-forge/commit/2a23cad10304a6b822720ec0ac4cfe5eb19d3a09)) +- **build:** build the contract for wasm32v1-none everywhere ([#940](https://github.com/Favourorg/Stellar-forge/issues/940)) ([0aa6df3](https://github.com/Favourorg/Stellar-forge/commit/0aa6df38bc25e5bf1941a7dbbafd12616a108505)) +- **security:** stop shipping Pinata credentials in the frontend bundle ([#921](https://github.com/Favourorg/Stellar-forge/issues/921)) ([2a23cad](https://github.com/Favourorg/Stellar-forge/commit/2a23cad10304a6b822720ec0ac4cfe5eb19d3a09)) # [1.4.0](https://github.com/Favourorg/Stellar-forge/compare/v1.3.2...v1.4.0) (2026-08-01) - ### Bug Fixes -* **contracts:** close remaining FWC26 audit issues ([787dc22](https://github.com/Favourorg/Stellar-forge/commit/787dc22d4272d0258856b6a31967c164dcefddda)), closes [909-#948](https://github.com/909-/issues/948) [#1022](https://github.com/Favourorg/Stellar-forge/issues/1022) [#910](https://github.com/Favourorg/Stellar-forge/issues/910) [#913](https://github.com/Favourorg/Stellar-forge/issues/913) [#916](https://github.com/Favourorg/Stellar-forge/issues/916) [#943](https://github.com/Favourorg/Stellar-forge/issues/943) -* **frontend:** fix Option encoding, map missing topics, add cap field ([fb3ee73](https://github.com/Favourorg/Stellar-forge/commit/fb3ee73daa47161d932d9f91585762223afa6a1a)), closes [#1022](https://github.com/Favourorg/Stellar-forge/issues/1022) [#917](https://github.com/Favourorg/Stellar-forge/issues/917) [#1022](https://github.com/Favourorg/Stellar-forge/issues/1022) [#943](https://github.com/Favourorg/Stellar-forge/issues/943) - +- **contracts:** close remaining FWC26 audit issues ([787dc22](https://github.com/Favourorg/Stellar-forge/commit/787dc22d4272d0258856b6a31967c164dcefddda)), closes [909-#948](https://github.com/909-/issues/948) [#1022](https://github.com/Favourorg/Stellar-forge/issues/1022) [#910](https://github.com/Favourorg/Stellar-forge/issues/910) [#913](https://github.com/Favourorg/Stellar-forge/issues/913) [#916](https://github.com/Favourorg/Stellar-forge/issues/916) [#943](https://github.com/Favourorg/Stellar-forge/issues/943) +- **frontend:** fix Option encoding, map missing topics, add cap field ([fb3ee73](https://github.com/Favourorg/Stellar-forge/commit/fb3ee73daa47161d932d9f91585762223afa6a1a)), closes [#1022](https://github.com/Favourorg/Stellar-forge/issues/1022) [#917](https://github.com/Favourorg/Stellar-forge/issues/917) [#1022](https://github.com/Favourorg/Stellar-forge/issues/1022) [#943](https://github.com/Favourorg/Stellar-forge/issues/943) ### Features -* **api:** add off-chain contract event indexer ([#943](https://github.com/Favourorg/Stellar-forge/issues/943)) ([19a9544](https://github.com/Favourorg/Stellar-forge/commit/19a9544f64827539f6c763c7f9c5b0df725b3cf0)) +- **api:** add off-chain contract event indexer ([#943](https://github.com/Favourorg/Stellar-forge/issues/943)) ([19a9544](https://github.com/Favourorg/Stellar-forge/commit/19a9544f64827539f6c763c7f9c5b0df725b3cf0)) ## [1.3.2](https://github.com/Favourorg/Stellar-forge/compare/v1.3.1...v1.3.2) (2026-07-28) - ### Bug Fixes -* **contract:** close open-proxy hole in burn ([#1021](https://github.com/Favourorg/Stellar-forge/issues/1021)) ([#1059](https://github.com/Favourorg/Stellar-forge/issues/1059)) ([895a621](https://github.com/Favourorg/Stellar-forge/commit/895a6218340f8540b8f961ddf47551c96f1c1dbc)) +- **contract:** close open-proxy hole in burn ([#1021](https://github.com/Favourorg/Stellar-forge/issues/1021)) ([#1059](https://github.com/Favourorg/Stellar-forge/issues/1059)) ([895a621](https://github.com/Favourorg/Stellar-forge/commit/895a6218340f8540b8f961ddf47551c96f1c1dbc)) ## [1.3.1](https://github.com/Favourorg/Stellar-forge/compare/v1.3.0...v1.3.1) (2026-07-27) - ### Bug Fixes -* **frontend:** handle every sendTransaction status explicitly ([#1020](https://github.com/Favourorg/Stellar-forge/issues/1020)) ([#1058](https://github.com/Favourorg/Stellar-forge/issues/1058)) ([70ebab6](https://github.com/Favourorg/Stellar-forge/commit/70ebab62bea7d7dc887e3ce6852a7f436b023083)), closes [#1056](https://github.com/Favourorg/Stellar-forge/issues/1056) [#1057](https://github.com/Favourorg/Stellar-forge/issues/1057) +- **frontend:** handle every sendTransaction status explicitly ([#1020](https://github.com/Favourorg/Stellar-forge/issues/1020)) ([#1058](https://github.com/Favourorg/Stellar-forge/issues/1058)) ([70ebab6](https://github.com/Favourorg/Stellar-forge/commit/70ebab62bea7d7dc887e3ce6852a7f436b023083)), closes [#1056](https://github.com/Favourorg/Stellar-forge/issues/1056) [#1057](https://github.com/Favourorg/Stellar-forge/issues/1057) # [1.3.0](https://github.com/Favourorg/Stellar-forge/compare/v1.2.0...v1.3.0) (2026-07-27) - ### Bug Fixes -* **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1036](https://github.com/Favourorg/Stellar-forge/issues/1036)) ([e3174cb](https://github.com/Favourorg/Stellar-forge/commit/e3174cb0bde98950c3bf7be8b97beb16a8cd8113)), closes [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) -* **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1037](https://github.com/Favourorg/Stellar-forge/issues/1037)) ([116d025](https://github.com/Favourorg/Stellar-forge/commit/116d0258ba1a58cfb22f5a12de9107b00e0323d5)), closes [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) -* align adm_upd topic and add CI drift detection ([#1032](https://github.com/Favourorg/Stellar-forge/issues/1032)) ([872baa9](https://github.com/Favourorg/Stellar-forge/commit/872baa9047675607156a731e1c9de78d4e9843fb)) -* **contracts:** add distribute_fee test coverage at realistic split sizes ([#918](https://github.com/Favourorg/Stellar-forge/issues/918)) ([#1025](https://github.com/Favourorg/Stellar-forge/issues/1025)) ([f9ec953](https://github.com/Favourorg/Stellar-forge/commit/f9ec95316a5ee9968094f12947f7a088cd2b24d1)), closes [#919](https://github.com/Favourorg/Stellar-forge/issues/919) -* **contracts:** charge exactly the required fee, not fee_payment ([#1035](https://github.com/Favourorg/Stellar-forge/issues/1035)) ([8654767](https://github.com/Favourorg/Stellar-forge/commit/86547670d6b45bf9a967ea59e26813b2670de6b5)), closes [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) [#1008](https://github.com/Favourorg/Stellar-forge/issues/1008) [#1008](https://github.com/Favourorg/Stellar-forge/issues/1008) -* **contracts:** make token-factory initialize atomic with deployment ([#1029](https://github.com/Favourorg/Stellar-forge/issues/1029)) ([3e12de2](https://github.com/Favourorg/Stellar-forge/commit/3e12de21ff69c7998ff0ad591bc8f066009e364f)), closes [#1005](https://github.com/Favourorg/Stellar-forge/issues/1005) -* **contracts:** move per-token bookkeeping to persistent storage ([#1034](https://github.com/Favourorg/Stellar-forge/issues/1034)) ([51c52bd](https://github.com/Favourorg/Stellar-forge/commit/51c52bd1bcb07eeda1744cd99f82a2816db6aa27)), closes [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) -* **contracts:** prove multi-step migrate pattern with synthetic v2 tests ([#919](https://github.com/Favourorg/Stellar-forge/issues/919)) ([#1026](https://github.com/Favourorg/Stellar-forge/issues/1026)) ([f9ef384](https://github.com/Favourorg/Stellar-forge/commit/f9ef3849f30d7af08473cd66268c0692def6da91)), closes [#918](https://github.com/Favourorg/Stellar-forge/issues/918) [#918](https://github.com/Favourorg/Stellar-forge/issues/918) -* **contracts:** repair broken merge artifacts on main ([#1041](https://github.com/Favourorg/Stellar-forge/issues/1041)) ([6524e58](https://github.com/Favourorg/Stellar-forge/commit/6524e58d86b00235622cb07e89d30a756df69f8e)), closes [1034/#1035](https://github.com/Favourorg/Stellar-forge/issues/1035) [#1033](https://github.com/Favourorg/Stellar-forge/issues/1033) [#1034](https://github.com/Favourorg/Stellar-forge/issues/1034) [#1025](https://github.com/Favourorg/Stellar-forge/issues/1025) -* **contracts:** seed max-supply counter with initial_supply ([#1006](https://github.com/Favourorg/Stellar-forge/issues/1006)) ([#1031](https://github.com/Favourorg/Stellar-forge/issues/1031)) ([4a3e90d](https://github.com/Favourorg/Stellar-forge/commit/4a3e90de113d45a28f67c765c4a7c07af38c7e44)) -* **frontend:** resolve token identity from contract, not events ([#1018](https://github.com/Favourorg/Stellar-forge/issues/1018)) ([#1030](https://github.com/Favourorg/Stellar-forge/issues/1030)) ([66bcb19](https://github.com/Favourorg/Stellar-forge/commit/66bcb1915e5199371a1b49f5b353e0aba0dfd86a)) -* **security:** validate uploaded image content, not client-declared M… ([#1055](https://github.com/Favourorg/Stellar-forge/issues/1055)) ([ab1f253](https://github.com/Favourorg/Stellar-forge/commit/ab1f25398d2c0a1c2a1a6418364423e5a0dfe577)), closes [#1002](https://github.com/Favourorg/Stellar-forge/issues/1002) [#1002](https://github.com/Favourorg/Stellar-forge/issues/1002) [#1056](https://github.com/Favourorg/Stellar-forge/issues/1056) [#1057](https://github.com/Favourorg/Stellar-forge/issues/1057) -* **token-factory:** bound fee-split recipient count to prevent resource-exhaustion griefing ([#1027](https://github.com/Favourorg/Stellar-forge/issues/1027)) ([becd28f](https://github.com/Favourorg/Stellar-forge/commit/becd28f8647eef2fa7e62a9d42b9626413c00216)) - +- **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1036](https://github.com/Favourorg/Stellar-forge/issues/1036)) ([e3174cb](https://github.com/Favourorg/Stellar-forge/commit/e3174cb0bde98950c3bf7be8b97beb16a8cd8113)), closes [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) +- **#1024,#1023:** fee-split edge cases and metadata URI validation ([#1037](https://github.com/Favourorg/Stellar-forge/issues/1037)) ([116d025](https://github.com/Favourorg/Stellar-forge/commit/116d0258ba1a58cfb22f5a12de9107b00e0323d5)), closes [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) [#1024](https://github.com/Favourorg/Stellar-forge/issues/1024) [#1023](https://github.com/Favourorg/Stellar-forge/issues/1023) +- align adm_upd topic and add CI drift detection ([#1032](https://github.com/Favourorg/Stellar-forge/issues/1032)) ([872baa9](https://github.com/Favourorg/Stellar-forge/commit/872baa9047675607156a731e1c9de78d4e9843fb)) +- **contracts:** add distribute_fee test coverage at realistic split sizes ([#918](https://github.com/Favourorg/Stellar-forge/issues/918)) ([#1025](https://github.com/Favourorg/Stellar-forge/issues/1025)) ([f9ec953](https://github.com/Favourorg/Stellar-forge/commit/f9ec95316a5ee9968094f12947f7a088cd2b24d1)), closes [#919](https://github.com/Favourorg/Stellar-forge/issues/919) +- **contracts:** charge exactly the required fee, not fee_payment ([#1035](https://github.com/Favourorg/Stellar-forge/issues/1035)) ([8654767](https://github.com/Favourorg/Stellar-forge/commit/86547670d6b45bf9a967ea59e26813b2670de6b5)), closes [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) [#1008](https://github.com/Favourorg/Stellar-forge/issues/1008) [#1008](https://github.com/Favourorg/Stellar-forge/issues/1008) +- **contracts:** make token-factory initialize atomic with deployment ([#1029](https://github.com/Favourorg/Stellar-forge/issues/1029)) ([3e12de2](https://github.com/Favourorg/Stellar-forge/commit/3e12de21ff69c7998ff0ad591bc8f066009e364f)), closes [#1005](https://github.com/Favourorg/Stellar-forge/issues/1005) +- **contracts:** move per-token bookkeeping to persistent storage ([#1034](https://github.com/Favourorg/Stellar-forge/issues/1034)) ([51c52bd](https://github.com/Favourorg/Stellar-forge/commit/51c52bd1bcb07eeda1744cd99f82a2816db6aa27)), closes [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) [#1007](https://github.com/Favourorg/Stellar-forge/issues/1007) +- **contracts:** prove multi-step migrate pattern with synthetic v2 tests ([#919](https://github.com/Favourorg/Stellar-forge/issues/919)) ([#1026](https://github.com/Favourorg/Stellar-forge/issues/1026)) ([f9ef384](https://github.com/Favourorg/Stellar-forge/commit/f9ef3849f30d7af08473cd66268c0692def6da91)), closes [#918](https://github.com/Favourorg/Stellar-forge/issues/918) [#918](https://github.com/Favourorg/Stellar-forge/issues/918) +- **contracts:** repair broken merge artifacts on main ([#1041](https://github.com/Favourorg/Stellar-forge/issues/1041)) ([6524e58](https://github.com/Favourorg/Stellar-forge/commit/6524e58d86b00235622cb07e89d30a756df69f8e)), closes [1034/#1035](https://github.com/Favourorg/Stellar-forge/issues/1035) [#1033](https://github.com/Favourorg/Stellar-forge/issues/1033) [#1034](https://github.com/Favourorg/Stellar-forge/issues/1034) [#1025](https://github.com/Favourorg/Stellar-forge/issues/1025) +- **contracts:** seed max-supply counter with initial_supply ([#1006](https://github.com/Favourorg/Stellar-forge/issues/1006)) ([#1031](https://github.com/Favourorg/Stellar-forge/issues/1031)) ([4a3e90d](https://github.com/Favourorg/Stellar-forge/commit/4a3e90de113d45a28f67c765c4a7c07af38c7e44)) +- **frontend:** resolve token identity from contract, not events ([#1018](https://github.com/Favourorg/Stellar-forge/issues/1018)) ([#1030](https://github.com/Favourorg/Stellar-forge/issues/1030)) ([66bcb19](https://github.com/Favourorg/Stellar-forge/commit/66bcb1915e5199371a1b49f5b353e0aba0dfd86a)) +- **security:** validate uploaded image content, not client-declared M… ([#1055](https://github.com/Favourorg/Stellar-forge/issues/1055)) ([ab1f253](https://github.com/Favourorg/Stellar-forge/commit/ab1f25398d2c0a1c2a1a6418364423e5a0dfe577)), closes [#1002](https://github.com/Favourorg/Stellar-forge/issues/1002) [#1002](https://github.com/Favourorg/Stellar-forge/issues/1002) [#1056](https://github.com/Favourorg/Stellar-forge/issues/1056) [#1057](https://github.com/Favourorg/Stellar-forge/issues/1057) +- **token-factory:** bound fee-split recipient count to prevent resource-exhaustion griefing ([#1027](https://github.com/Favourorg/Stellar-forge/issues/1027)) ([becd28f](https://github.com/Favourorg/Stellar-forge/commit/becd28f8647eef2fa7e62a9d42b9626413c00216)) ### Features -* **frontend:** implement paginated global token listing (getAllTokens) ([#1028](https://github.com/Favourorg/Stellar-forge/issues/1028)) ([0e1b51e](https://github.com/Favourorg/Stellar-forge/commit/0e1b51e2590b3c23468f893f13e77e5f2eeb592a)), closes [#1017](https://github.com/Favourorg/Stellar-forge/issues/1017) +- **frontend:** implement paginated global token listing (getAllTokens) ([#1028](https://github.com/Favourorg/Stellar-forge/issues/1028)) ([0e1b51e](https://github.com/Favourorg/Stellar-forge/commit/0e1b51e2590b3c23468f893f13e77e5f2eeb592a)), closes [#1017](https://github.com/Favourorg/Stellar-forge/issues/1017) # [1.2.0](https://github.com/Favourorg/Stellar-forge/compare/v1.1.0...v1.2.0) (2026-07-21) - ### Bug Fixes -* **deps:** add Dependabot fuzz coverage and auto-merge policy ([#985](https://github.com/Favourorg/Stellar-forge/issues/985)) ([2247b9f](https://github.com/Favourorg/Stellar-forge/commit/2247b9f0cb3343708d5eebb461280d7e558a5b38)), closes [#941](https://github.com/Favourorg/Stellar-forge/issues/941) - +- **deps:** add Dependabot fuzz coverage and auto-merge policy ([#985](https://github.com/Favourorg/Stellar-forge/issues/985)) ([2247b9f](https://github.com/Favourorg/Stellar-forge/commit/2247b9f0cb3343708d5eebb461280d7e558a5b38)), closes [#941](https://github.com/Favourorg/Stellar-forge/issues/941) ### Features -* **frontend:** verify deployed token WASM hash against factory state ([#986](https://github.com/Favourorg/Stellar-forge/issues/986)) ([6d1566a](https://github.com/Favourorg/Stellar-forge/commit/6d1566a8416e1ac44860fbb6a1395e062548141a)), closes [#925](https://github.com/Favourorg/Stellar-forge/issues/925) [hi#severity](https://github.com/hi/issues/severity) [#982](https://github.com/Favourorg/Stellar-forge/issues/982) [#984](https://github.com/Favourorg/Stellar-forge/issues/984) [#984](https://github.com/Favourorg/Stellar-forge/issues/984) [#984](https://github.com/Favourorg/Stellar-forge/issues/984) [#982](https://github.com/Favourorg/Stellar-forge/issues/982) +- **frontend:** verify deployed token WASM hash against factory state ([#986](https://github.com/Favourorg/Stellar-forge/issues/986)) ([6d1566a](https://github.com/Favourorg/Stellar-forge/commit/6d1566a8416e1ac44860fbb6a1395e062548141a)), closes [#925](https://github.com/Favourorg/Stellar-forge/issues/925) [hi#severity](https://github.com/hi/issues/severity) [#982](https://github.com/Favourorg/Stellar-forge/issues/982) [#984](https://github.com/Favourorg/Stellar-forge/issues/984) [#984](https://github.com/Favourorg/Stellar-forge/issues/984) [#984](https://github.com/Favourorg/Stellar-forge/issues/984) [#982](https://github.com/Favourorg/Stellar-forge/issues/982) # [1.1.0](https://github.com/Favourorg/Stellar-forge/compare/v1.0.0...v1.1.0) (2026-07-20) - ### Features -* **security:** add triage and waiver workflow for audit findings ([#981](https://github.com/Favourorg/Stellar-forge/issues/981)) ([aa0ceab](https://github.com/Favourorg/Stellar-forge/commit/aa0ceab6d134bb7706f4bdb03f4e591bc5eba1ee)), closes [hi#or-above](https://github.com/hi/issues/or-above) [#939](https://github.com/Favourorg/Stellar-forge/issues/939) +- **security:** add triage and waiver workflow for audit findings ([#981](https://github.com/Favourorg/Stellar-forge/issues/981)) ([aa0ceab](https://github.com/Favourorg/Stellar-forge/commit/aa0ceab6d134bb7706f4bdb03f4e591bc5eba1ee)), closes [hi#or-above](https://github.com/hi/issues/or-above) [#939](https://github.com/Favourorg/Stellar-forge/issues/939) # 1.0.0 (2026-07-20) - ### Bug Fixes -* [#741](https://github.com/Favourorg/Stellar-forge/issues/741) AdminPanel restricted to admin address only ([7b2b8c2](https://github.com/Favourorg/Stellar-forge/commit/7b2b8c23d40955b39ea300acea24cfeef851d32d)) -* **#854:** format useTransactionHistory.ts to match project Prettier style (remove semicolons) ([8e7b12b](https://github.com/Favourorg/Stellar-forge/commit/8e7b12b757780a3570ec5b425ba61bcf4a23d6b1)), closes [#854](https://github.com/Favourorg/Stellar-forge/issues/854) -* **#855:** eliminate CSP duplication by generating index.html meta tag from policy.ts ([1dc325a](https://github.com/Favourorg/Stellar-forge/commit/1dc325a503f0f41eb78e5220e1252b4afcb5ee13)), closes [#855](https://github.com/Favourorg/Stellar-forge/issues/855) -* **#932:** consolidate useTransactionPolling into useTransaction.ts ([#956](https://github.com/Favourorg/Stellar-forge/issues/956)) ([28a84b6](https://github.com/Favourorg/Stellar-forge/commit/28a84b67df80e8f6c155e97da6f54704a36113cb)), closes [#932](https://github.com/Favourorg/Stellar-forge/issues/932) [#932](https://github.com/Favourorg/Stellar-forge/issues/932) -* **#944:** add txHash, network, contractId Sentry tagging on transaction failures ([#952](https://github.com/Favourorg/Stellar-forge/issues/952)) ([9c213d0](https://github.com/Favourorg/Stellar-forge/commit/9c213d09b089f5704d2748ccc7e3aa2b4fc18a15)), closes [#944](https://github.com/Favourorg/Stellar-forge/issues/944) [#944](https://github.com/Favourorg/Stellar-forge/issues/944) -* **#945:** document batch resource limits and add frontend size cap ([#953](https://github.com/Favourorg/Stellar-forge/issues/953)) ([8555f65](https://github.com/Favourorg/Stellar-forge/commit/8555f65acc16ff60cd3108eb533d836ca7fcd0f2)), closes [#945](https://github.com/Favourorg/Stellar-forge/issues/945) [#945](https://github.com/Favourorg/Stellar-forge/issues/945) -* **#947:** add incident response runbook and break-glass recovery docs ([#954](https://github.com/Favourorg/Stellar-forge/issues/954)) ([0546342](https://github.com/Favourorg/Stellar-forge/commit/054634208dd995ce8daacbd83199c6c8e3547c2a)), closes [#947](https://github.com/Favourorg/Stellar-forge/issues/947) [#9](https://github.com/Favourorg/Stellar-forge/issues/9) [#947](https://github.com/Favourorg/Stellar-forge/issues/947) -* accept decimals=0 in validateTokenParams ([56cb8d9](https://github.com/Favourorg/Stellar-forge/commit/56cb8d961c2d5e421f5391b6d31587ad52013d4b)) -* add bounds validation to token metadata type guard (CWE-1236) ([#964](https://github.com/Favourorg/Stellar-forge/issues/964)) ([ab4cb5c](https://github.com/Favourorg/Stellar-forge/commit/ab4cb5c31ea6ded2673ee8d4dc61d11f2469d5a7)) -* add BurnAmountExceedsBalance check in burn function ([1113068](https://github.com/Favourorg/Stellar-forge/commit/1113068ceb02e464c40066021ca24279dc4753ab)) -* add CI drift check for contract ABI documentation - Closes [#946](https://github.com/Favourorg/Stellar-forge/issues/946) ([#949](https://github.com/Favourorg/Stellar-forge/issues/949)) ([8e67454](https://github.com/Favourorg/Stellar-forge/commit/8e67454a4a4d41c8fe1232eb0d2faebce79f9c6d)) -* add env var validation and misconfiguration screen ([f66f1d5](https://github.com/Favourorg/Stellar-forge/commit/f66f1d5c144e9e96ddb451e4feeffca41e950b3d)) -* add esbuild as a direct devDependency for Storybook CI build ([512b11e](https://github.com/Favourorg/Stellar-forge/commit/512b11e8cad65979e4fbbdac073ddb8dc5ba1fa8)) -* add formula-injection guard to CSV export (CWE-1236) ([#963](https://github.com/Favourorg/Stellar-forge/issues/963)) ([bff7012](https://github.com/Favourorg/Stellar-forge/commit/bff70125f81172ece961c8c4f9f2a215e6f746ce)) -* add missing build step to E2E job, fix sitemap script crash ([535955c](https://github.com/Favourorg/Stellar-forge/commit/535955c34bbd6b3877fde7f5a29b42288352cdcc)) -* add missing imports for mobile responsive components ([0b89740](https://github.com/Favourorg/Stellar-forge/commit/0b89740d64d35bfacddd14b8c6b5a7c4933a4c7b)) -* add standalone network support and fix E2E test mocks ([a78f8de](https://github.com/Favourorg/Stellar-forge/commit/a78f8deef5c21e74f3b391726a60636692a242c3)) -* **analytics:** add opt-out tests, CI bypass check, and compliance ADR ([#965](https://github.com/Favourorg/Stellar-forge/issues/965)) ([180f672](https://github.com/Favourorg/Stellar-forge/commit/180f6725d2f82fa5a068687e428886e85179edd3)), closes [#948](https://github.com/Favourorg/Stellar-forge/issues/948) -* audit follow-ups — restore tx polling backoff, fix wasm target, drop orphan form ([05409eb](https://github.com/Favourorg/Stellar-forge/commit/05409eb55f4e3ff2797fce06d631fc94553a0239)), closes [#852](https://github.com/Favourorg/Stellar-forge/issues/852) [#732](https://github.com/Favourorg/Stellar-forge/issues/732) [813/#814](https://github.com/Favourorg/Stellar-forge/issues/814) -* **ci:** remove continue-on-error from fuzz steps, add PR smoke job ([#937](https://github.com/Favourorg/Stellar-forge/issues/937)) ([#966](https://github.com/Favourorg/Stellar-forge/issues/966)) ([000458f](https://github.com/Favourorg/Stellar-forge/commit/000458f8ffde77f136476ea37f2758169f212e07)) -* clear cargo clippy -D warnings findings in token-factory ([2a27a8f](https://github.com/Favourorg/Stellar-forge/commit/2a27a8fff3e0b78b5173696166315c1470211a09)) -* complete contract test suite with all error variants covered ([5f8320d](https://github.com/Favourorg/Stellar-forge/commit/5f8320d7b14d3a93339ed3f82779d4763a0717b7)) -* **contract:** front-load batch validation and document Soroban transaction atomicity ([#915](https://github.com/Favourorg/Stellar-forge/issues/915)) ([#974](https://github.com/Favourorg/Stellar-forge/issues/974)) ([b60868f](https://github.com/Favourorg/Stellar-forge/commit/b60868f0363e8e6c1c89927cfee42fecef7af34a)) -* **contracts:** add crash-to-regression-test process with fuzz corpus infrastructure ([#951](https://github.com/Favourorg/Stellar-forge/issues/951)) ([9428b7d](https://github.com/Favourorg/Stellar-forge/commit/9428b7d209366e9ba62ef72359c902cf9beb79b3)), closes [#938](https://github.com/Favourorg/Stellar-forge/issues/938) -* **contracts:** add integer overflow protection in fee arithmetic ([18622f1](https://github.com/Favourorg/Stellar-forge/commit/18622f1777201ba92c4db2ef60928faa4c053de3)), closes [#513](https://github.com/Favourorg/Stellar-forge/issues/513) -* correct useLocalStorage syntax error and variable reference ([232fc52](https://github.com/Favourorg/Stellar-forge/commit/232fc520e4df8a4d1345e67e05084ae32252fe5e)) -* dedupe token-validation rules in validation.ts ([d3012c2](https://github.com/Favourorg/Stellar-forge/commit/d3012c2c310f31135a463f13482af36ec9b1dc46)), closes [#845](https://github.com/Favourorg/Stellar-forge/issues/845) -* downgrade vite to v6 for Storybook compatibility ([c2f071b](https://github.com/Favourorg/Stellar-forge/commit/c2f071bb75ced96669d27f11cec13e11d9c83358)) -* **e2e:** add token-list-container class and show 6 trailing address chars ([9fcfff3](https://github.com/Favourorg/Stellar-forge/commit/9fcfff3398df79dd9ad987ff4ad51d15409f78b6)) -* **e2e:** prevent watcher auto-connect by not responding to REQUEST_NETWORK_DETAILS ([9649702](https://github.com/Favourorg/Stellar-forge/commit/9649702d0793d0e489bb9eb2caba0217f3ab99dc)) -* exclude fuzz crate from workspace to prevent wasm32 compilation errors ([b3f09f2](https://github.com/Favourorg/Stellar-forge/commit/b3f09f208486b314a10fd2f8061b90631fa5df3a)) -* expand .gitignore to prevent accidental commits of local artifacts ([1da56fe](https://github.com/Favourorg/Stellar-forge/commit/1da56fe00394ccbbff2a86d0de8fa7cf24356924)), closes [#835](https://github.com/Favourorg/Stellar-forge/issues/835) -* **frontend:** clear typecheck errors and prettier drift masked by red CI ([82994b9](https://github.com/Favourorg/Stellar-forge/commit/82994b977781c0b616e68b29fa1e1859765b0ac9)) -* **frontend:** close network-mismatch signing window with a fresh pre-sign check ([#961](https://github.com/Favourorg/Stellar-forge/issues/961)) ([7619e99](https://github.com/Favourorg/Stellar-forge/commit/7619e9960d68ad73f6fb67ee0f4f9d11d6ee6ba6)), closes [#927](https://github.com/Favourorg/Stellar-forge/issues/927) -* **frontend:** close unclosed PR wrapper in App.tsx and remove duplicate route entries ([4f9442b](https://github.com/Favourorg/Stellar-forge/commit/4f9442bda20864966521c36f1ed4272c52f56dd2)) -* **frontend:** establish transaction reconciliation policy and add phantom-entry guards ([#955](https://github.com/Favourorg/Stellar-forge/issues/955)) ([1372af1](https://github.com/Favourorg/Stellar-forge/commit/1372af165a869a1814ef9b43d22c9e9f507190f2)), closes [#933](https://github.com/Favourorg/Stellar-forge/issues/933) -* **frontend:** filter-aware cache key, stable useCallback deps, re-fetch on filter change ([62d2c8c](https://github.com/Favourorg/Stellar-forge/commit/62d2c8c3aaba49c1099b30db5e3956747b407b9a)) -* **frontend:** implement the CSV formula-injection guard its tests expected ([59839b6](https://github.com/Favourorg/Stellar-forge/commit/59839b603cf7a84d782a740ff455e9bc9748ed62)), closes [#963](https://github.com/Favourorg/Stellar-forge/issues/963) -* **frontend:** make token-detail routes public for deep links ([#880](https://github.com/Favourorg/Stellar-forge/issues/880)) ([971e14b](https://github.com/Favourorg/Stellar-forge/commit/971e14b24097a4f08688b097225728ed22955c6e)) -* **frontend:** only mount OnboardingModal on Help click, not first-visit ([87d3ce4](https://github.com/Favourorg/Stellar-forge/commit/87d3ce41a764067f90f0384ce795f6111fdcaeec)) -* **frontend:** paginate factory event fetch instead of silently capping "all tokens" ([#962](https://github.com/Favourorg/Stellar-forge/issues/962)) ([b480f56](https://github.com/Favourorg/Stellar-forge/commit/b480f56b8f935802aab26d2384efcb3eb3da9080)), closes [#35](https://github.com/Favourorg/Stellar-forge/issues/35) -* **frontend:** pay real base_fee, surface FeeDisplay in mint, block writes on network mismatch ([6d5697d](https://github.com/Favourorg/Stellar-forge/commit/6d5697d3f661be16c4fefccdb1a71f5b5d35734b)) -* **frontend:** remove exhaustive-deps suppressions, fix dep arrays ([a8fcf34](https://github.com/Favourorg/Stellar-forge/commit/a8fcf3463afe36bacf28f5f1f259eb5f8e7ca845)) -* **frontend:** resolve merge fallout — format, getMetadata validation, no-this-alias ([4e0d770](https://github.com/Favourorg/Stellar-forge/commit/4e0d77063f0d8b10f23cc9176ea2217bf9337b08)) -* **frontend:** source FeeDisplay fees from useFactoryState, not the singleton ([e388e7a](https://github.com/Favourorg/Stellar-forge/commit/e388e7aacaf66708e01aba263121bd9b932895b2)) -* **frontend:** stop passing a decimal XLM string to formatXLM ([d23be61](https://github.com/Favourorg/Stellar-forge/commit/d23be616d378af583289ce5544de20673eeb5fda)) -* **frontend:** track Horizon paging_token and pass cursor on load-more ([aa6e15b](https://github.com/Favourorg/Stellar-forge/commit/aa6e15b235bda5842fed1e8aa5848a2e06b04959)) -* **frontend:** unify transaction poll backoff into shared utility ([#960](https://github.com/Favourorg/Stellar-forge/issues/960)) ([2ad85fc](https://github.com/Favourorg/Stellar-forge/commit/2ad85fc7f43c40a66746519eccaf89cb5147e53c)) -* **frontend:** wire orphaned features, fix standalone network, add typecheck gate ([c14d1b1](https://github.com/Favourorg/Stellar-forge/commit/c14d1b108ef210ede1d007f231cd4797f844fe26)) -* **ipfs:** retry image upload on transient Pinata errors ([26a2005](https://github.com/Favourorg/Stellar-forge/commit/26a2005ebfbe5c27c7f132c3f0a031d5c750ac30)), closes [#743](https://github.com/Favourorg/Stellar-forge/issues/743) -* **ipfs:** validate getMetadata response shape before returning ([7183346](https://github.com/Favourorg/Stellar-forge/commit/71833467e8e0aa7c8a770d2905056227e721378c)), closes [#849](https://github.com/Favourorg/Stellar-forge/issues/849) -* make all 202 tests pass ([1043432](https://github.com/Favourorg/Stellar-forge/commit/1043432dcdf6307385661d7261fd8f73bcae6923)) -* pin esbuild/globals devDeps and apply npm audit fixes ([6ccd8c3](https://github.com/Favourorg/Stellar-forge/commit/6ccd8c3418b8617052bd8c290231cabad9d82119)) -* provide VITE_TOKEN_WASM_HASH in E2E CI job ([64c1a5b](https://github.com/Favourorg/Stellar-forge/commit/64c1a5b24f90f4685b1690b8653e620768924240)) -* real bugs surfaced while restoring lint/test coverage ([8434f56](https://github.com/Favourorg/Stellar-forge/commit/8434f5688c3f8877513c5931eef26bf93b85091f)) -* redesign fee transfer and token deployment per issue spec ([e7b8c9e](https://github.com/Favourorg/Stellar-forge/commit/e7b8c9e7f0a77cb618b39afa0b91ea6ac87c5b21)) -* refactor build system, fix contract errors, fix dark mode toggle ([85751f8](https://github.com/Favourorg/Stellar-forge/commit/85751f85239640acbae8197feccb14ff63724c16)) -* **release:** add @actions/io to satisfy @actions/exec's undeclared import ([cd21fdc](https://github.com/Favourorg/Stellar-forge/commit/cd21fdc70110759165e95d85803d48f15dd7225f)) -* **release:** disable husky hooks in the release workflow ([5429060](https://github.com/Favourorg/Stellar-forge/commit/5429060a58cf30265f835f3954a420de043452df)) -* repair local Stellar network startup in E2E CI job ([5aa9026](https://github.com/Favourorg/Stellar-forge/commit/5aa90265077404369cfe81c6a96eb94017075893)) -* replace console.error with logger in CreateToken, TokenForm, MetadataUploadForm ([24805af](https://github.com/Favourorg/Stellar-forge/commit/24805af56b93e60392a4817ba8708c29960dd043)), closes [#848](https://github.com/Favourorg/Stellar-forge/issues/848) -* replace invalid checksum address in validation test ([64ac45a](https://github.com/Favourorg/Stellar-forge/commit/64ac45ae4179ede5aa0fce9533ffaae640ef2084)) -* resolve build failure blocking strict mode verification ([e3370f5](https://github.com/Favourorg/Stellar-forge/commit/e3370f50dec6af5a2780d35d7e11462ecf0c3145)) -* resolve Horizon URL from active network config in useTransactionHistory ([2c25a2d](https://github.com/Favourorg/Stellar-forge/commit/2c25a2d2d3b43a72c5453e84f2e2707b4d443696)), closes [#837](https://github.com/Favourorg/Stellar-forge/issues/837) -* restore ESLint v9 flat config ([a85d008](https://github.com/Favourorg/Stellar-forge/commit/a85d008e18a7f925eff1fd5a7361e624754f28cf)) -* **routing:** fix deep-link for /token/:address and add e2e tests ([1eb308a](https://github.com/Favourorg/Stellar-forge/commit/1eb308ab9014c595c30aa3868e9d3e4b87278470)) -* stop E2E app crash on unknown network and repair Freighter mock ([232afee](https://github.com/Favourorg/Stellar-forge/commit/232afee01997300d0fb64ebbe5101d9c11c520fb)) -* **storybook:** finish the Storybook 10 migration ([a66a453](https://github.com/Favourorg/Stellar-forge/commit/a66a453846c86dd2ee83fcb347380b26af4c66ef)), closes [#893](https://github.com/Favourorg/Stellar-forge/issues/893) -* **token-factory:** enforce strict clippy linting for contract code ([686b143](https://github.com/Favourorg/Stellar-forge/commit/686b143cec68646bffeb75790ac317a450742f1f)) -* **token-factory:** extend reentrancy guard to all state-mutating entrypoints ([#972](https://github.com/Favourorg/Stellar-forge/issues/972)) ([45a1a9c](https://github.com/Favourorg/Stellar-forge/commit/45a1a9c1f077d7dbb4e6989ce6ccf42195e88fce)) -* **token-factory:** reject negative base_fee and metadata_fee ([#973](https://github.com/Favourorg/Stellar-forge/issues/973)) ([e3cdd5e](https://github.com/Favourorg/Stellar-forge/commit/e3cdd5eb5de4962381800beaa58853b45ee4b46d)) -* **token-factory:** store token_wasm_hash in FactoryState ([7de1635](https://github.com/Favourorg/Stellar-forge/commit/7de1635b752553f7166f4e6838620a4dd8d540cc)), closes [#543](https://github.com/Favourorg/Stellar-forge/issues/543) -* **ui:** sanitize and validate token name/symbol inputs ([1e4e2e7](https://github.com/Favourorg/Stellar-forge/commit/1e4e2e74f4f0dec3fa06cd44bc4892e76dd421d7)) -* upgrade soroban-sdk to 25.x and fix wasm build ([1e098e1](https://github.com/Favourorg/Stellar-forge/commit/1e098e149830f6a10e319bd4ac26ef6db8c1c13a)) -* Use correct validation function name in MetadataUploadForm ([b8802cf](https://github.com/Favourorg/Stellar-forge/commit/b8802cfd55f2f9f80e2ec76387c9d91b14bce9e5)) -* use dedicated fee_token for all fee transfers in factory contract ([14db340](https://github.com/Favourorg/Stellar-forge/commit/14db340019273fbbd6538c240d765aba96906ec5)) -* use formatXLM and stroopsToXLM in FeeDisplay and add conversion test ([65b5d94](https://github.com/Favourorg/Stellar-forge/commit/65b5d944ea82d68e68dd816830751533bf58eca2)) -* validate hexToBytes input is exactly 64 hex chars ([4165f9f](https://github.com/Favourorg/Stellar-forge/commit/4165f9f3a9d7285fe3ae50c5784f257c73d77716)), closes [#836](https://github.com/Favourorg/Stellar-forge/issues/836) -* validate token supply before minting to prevent u128 overflow ([#959](https://github.com/Favourorg/Stellar-forge/issues/959)) ([d4027c8](https://github.com/Favourorg/Stellar-forge/commit/d4027c81e69c2d2434374a41e8d2bd514a647c26)), closes [#909](https://github.com/Favourorg/Stellar-forge/issues/909) -* **validation:** use StrKey checksum validation for Stellar addresses ([c55f0f4](https://github.com/Favourorg/Stellar-forge/commit/c55f0f49232a10494906398930488a8eb7e7f9bc)) -* **wallet:** clear all state and token cache on disconnect ([a2b1ed3](https://github.com/Favourorg/Stellar-forge/commit/a2b1ed36c3413c37eca259e389307a2f6f06f556)) - +- [#741](https://github.com/Favourorg/Stellar-forge/issues/741) AdminPanel restricted to admin address only ([7b2b8c2](https://github.com/Favourorg/Stellar-forge/commit/7b2b8c23d40955b39ea300acea24cfeef851d32d)) +- **#854:** format useTransactionHistory.ts to match project Prettier style (remove semicolons) ([8e7b12b](https://github.com/Favourorg/Stellar-forge/commit/8e7b12b757780a3570ec5b425ba61bcf4a23d6b1)), closes [#854](https://github.com/Favourorg/Stellar-forge/issues/854) +- **#855:** eliminate CSP duplication by generating index.html meta tag from policy.ts ([1dc325a](https://github.com/Favourorg/Stellar-forge/commit/1dc325a503f0f41eb78e5220e1252b4afcb5ee13)), closes [#855](https://github.com/Favourorg/Stellar-forge/issues/855) +- **#932:** consolidate useTransactionPolling into useTransaction.ts ([#956](https://github.com/Favourorg/Stellar-forge/issues/956)) ([28a84b6](https://github.com/Favourorg/Stellar-forge/commit/28a84b67df80e8f6c155e97da6f54704a36113cb)), closes [#932](https://github.com/Favourorg/Stellar-forge/issues/932) [#932](https://github.com/Favourorg/Stellar-forge/issues/932) +- **#944:** add txHash, network, contractId Sentry tagging on transaction failures ([#952](https://github.com/Favourorg/Stellar-forge/issues/952)) ([9c213d0](https://github.com/Favourorg/Stellar-forge/commit/9c213d09b089f5704d2748ccc7e3aa2b4fc18a15)), closes [#944](https://github.com/Favourorg/Stellar-forge/issues/944) [#944](https://github.com/Favourorg/Stellar-forge/issues/944) +- **#945:** document batch resource limits and add frontend size cap ([#953](https://github.com/Favourorg/Stellar-forge/issues/953)) ([8555f65](https://github.com/Favourorg/Stellar-forge/commit/8555f65acc16ff60cd3108eb533d836ca7fcd0f2)), closes [#945](https://github.com/Favourorg/Stellar-forge/issues/945) [#945](https://github.com/Favourorg/Stellar-forge/issues/945) +- **#947:** add incident response runbook and break-glass recovery docs ([#954](https://github.com/Favourorg/Stellar-forge/issues/954)) ([0546342](https://github.com/Favourorg/Stellar-forge/commit/054634208dd995ce8daacbd83199c6c8e3547c2a)), closes [#947](https://github.com/Favourorg/Stellar-forge/issues/947) [#9](https://github.com/Favourorg/Stellar-forge/issues/9) [#947](https://github.com/Favourorg/Stellar-forge/issues/947) +- accept decimals=0 in validateTokenParams ([56cb8d9](https://github.com/Favourorg/Stellar-forge/commit/56cb8d961c2d5e421f5391b6d31587ad52013d4b)) +- add bounds validation to token metadata type guard (CWE-1236) ([#964](https://github.com/Favourorg/Stellar-forge/issues/964)) ([ab4cb5c](https://github.com/Favourorg/Stellar-forge/commit/ab4cb5c31ea6ded2673ee8d4dc61d11f2469d5a7)) +- add BurnAmountExceedsBalance check in burn function ([1113068](https://github.com/Favourorg/Stellar-forge/commit/1113068ceb02e464c40066021ca24279dc4753ab)) +- add CI drift check for contract ABI documentation - Closes [#946](https://github.com/Favourorg/Stellar-forge/issues/946) ([#949](https://github.com/Favourorg/Stellar-forge/issues/949)) ([8e67454](https://github.com/Favourorg/Stellar-forge/commit/8e67454a4a4d41c8fe1232eb0d2faebce79f9c6d)) +- add env var validation and misconfiguration screen ([f66f1d5](https://github.com/Favourorg/Stellar-forge/commit/f66f1d5c144e9e96ddb451e4feeffca41e950b3d)) +- add esbuild as a direct devDependency for Storybook CI build ([512b11e](https://github.com/Favourorg/Stellar-forge/commit/512b11e8cad65979e4fbbdac073ddb8dc5ba1fa8)) +- add formula-injection guard to CSV export (CWE-1236) ([#963](https://github.com/Favourorg/Stellar-forge/issues/963)) ([bff7012](https://github.com/Favourorg/Stellar-forge/commit/bff70125f81172ece961c8c4f9f2a215e6f746ce)) +- add missing build step to E2E job, fix sitemap script crash ([535955c](https://github.com/Favourorg/Stellar-forge/commit/535955c34bbd6b3877fde7f5a29b42288352cdcc)) +- add missing imports for mobile responsive components ([0b89740](https://github.com/Favourorg/Stellar-forge/commit/0b89740d64d35bfacddd14b8c6b5a7c4933a4c7b)) +- add standalone network support and fix E2E test mocks ([a78f8de](https://github.com/Favourorg/Stellar-forge/commit/a78f8deef5c21e74f3b391726a60636692a242c3)) +- **analytics:** add opt-out tests, CI bypass check, and compliance ADR ([#965](https://github.com/Favourorg/Stellar-forge/issues/965)) ([180f672](https://github.com/Favourorg/Stellar-forge/commit/180f6725d2f82fa5a068687e428886e85179edd3)), closes [#948](https://github.com/Favourorg/Stellar-forge/issues/948) +- audit follow-ups — restore tx polling backoff, fix wasm target, drop orphan form ([05409eb](https://github.com/Favourorg/Stellar-forge/commit/05409eb55f4e3ff2797fce06d631fc94553a0239)), closes [#852](https://github.com/Favourorg/Stellar-forge/issues/852) [#732](https://github.com/Favourorg/Stellar-forge/issues/732) [813/#814](https://github.com/Favourorg/Stellar-forge/issues/814) +- **ci:** remove continue-on-error from fuzz steps, add PR smoke job ([#937](https://github.com/Favourorg/Stellar-forge/issues/937)) ([#966](https://github.com/Favourorg/Stellar-forge/issues/966)) ([000458f](https://github.com/Favourorg/Stellar-forge/commit/000458f8ffde77f136476ea37f2758169f212e07)) +- clear cargo clippy -D warnings findings in token-factory ([2a27a8f](https://github.com/Favourorg/Stellar-forge/commit/2a27a8fff3e0b78b5173696166315c1470211a09)) +- complete contract test suite with all error variants covered ([5f8320d](https://github.com/Favourorg/Stellar-forge/commit/5f8320d7b14d3a93339ed3f82779d4763a0717b7)) +- **contract:** front-load batch validation and document Soroban transaction atomicity ([#915](https://github.com/Favourorg/Stellar-forge/issues/915)) ([#974](https://github.com/Favourorg/Stellar-forge/issues/974)) ([b60868f](https://github.com/Favourorg/Stellar-forge/commit/b60868f0363e8e6c1c89927cfee42fecef7af34a)) +- **contracts:** add crash-to-regression-test process with fuzz corpus infrastructure ([#951](https://github.com/Favourorg/Stellar-forge/issues/951)) ([9428b7d](https://github.com/Favourorg/Stellar-forge/commit/9428b7d209366e9ba62ef72359c902cf9beb79b3)), closes [#938](https://github.com/Favourorg/Stellar-forge/issues/938) +- **contracts:** add integer overflow protection in fee arithmetic ([18622f1](https://github.com/Favourorg/Stellar-forge/commit/18622f1777201ba92c4db2ef60928faa4c053de3)), closes [#513](https://github.com/Favourorg/Stellar-forge/issues/513) +- correct useLocalStorage syntax error and variable reference ([232fc52](https://github.com/Favourorg/Stellar-forge/commit/232fc520e4df8a4d1345e67e05084ae32252fe5e)) +- dedupe token-validation rules in validation.ts ([d3012c2](https://github.com/Favourorg/Stellar-forge/commit/d3012c2c310f31135a463f13482af36ec9b1dc46)), closes [#845](https://github.com/Favourorg/Stellar-forge/issues/845) +- downgrade vite to v6 for Storybook compatibility ([c2f071b](https://github.com/Favourorg/Stellar-forge/commit/c2f071bb75ced96669d27f11cec13e11d9c83358)) +- **e2e:** add token-list-container class and show 6 trailing address chars ([9fcfff3](https://github.com/Favourorg/Stellar-forge/commit/9fcfff3398df79dd9ad987ff4ad51d15409f78b6)) +- **e2e:** prevent watcher auto-connect by not responding to REQUEST_NETWORK_DETAILS ([9649702](https://github.com/Favourorg/Stellar-forge/commit/9649702d0793d0e489bb9eb2caba0217f3ab99dc)) +- exclude fuzz crate from workspace to prevent wasm32 compilation errors ([b3f09f2](https://github.com/Favourorg/Stellar-forge/commit/b3f09f208486b314a10fd2f8061b90631fa5df3a)) +- expand .gitignore to prevent accidental commits of local artifacts ([1da56fe](https://github.com/Favourorg/Stellar-forge/commit/1da56fe00394ccbbff2a86d0de8fa7cf24356924)), closes [#835](https://github.com/Favourorg/Stellar-forge/issues/835) +- **frontend:** clear typecheck errors and prettier drift masked by red CI ([82994b9](https://github.com/Favourorg/Stellar-forge/commit/82994b977781c0b616e68b29fa1e1859765b0ac9)) +- **frontend:** close network-mismatch signing window with a fresh pre-sign check ([#961](https://github.com/Favourorg/Stellar-forge/issues/961)) ([7619e99](https://github.com/Favourorg/Stellar-forge/commit/7619e9960d68ad73f6fb67ee0f4f9d11d6ee6ba6)), closes [#927](https://github.com/Favourorg/Stellar-forge/issues/927) +- **frontend:** close unclosed PR wrapper in App.tsx and remove duplicate route entries ([4f9442b](https://github.com/Favourorg/Stellar-forge/commit/4f9442bda20864966521c36f1ed4272c52f56dd2)) +- **frontend:** establish transaction reconciliation policy and add phantom-entry guards ([#955](https://github.com/Favourorg/Stellar-forge/issues/955)) ([1372af1](https://github.com/Favourorg/Stellar-forge/commit/1372af165a869a1814ef9b43d22c9e9f507190f2)), closes [#933](https://github.com/Favourorg/Stellar-forge/issues/933) +- **frontend:** filter-aware cache key, stable useCallback deps, re-fetch on filter change ([62d2c8c](https://github.com/Favourorg/Stellar-forge/commit/62d2c8c3aaba49c1099b30db5e3956747b407b9a)) +- **frontend:** implement the CSV formula-injection guard its tests expected ([59839b6](https://github.com/Favourorg/Stellar-forge/commit/59839b603cf7a84d782a740ff455e9bc9748ed62)), closes [#963](https://github.com/Favourorg/Stellar-forge/issues/963) +- **frontend:** make token-detail routes public for deep links ([#880](https://github.com/Favourorg/Stellar-forge/issues/880)) ([971e14b](https://github.com/Favourorg/Stellar-forge/commit/971e14b24097a4f08688b097225728ed22955c6e)) +- **frontend:** only mount OnboardingModal on Help click, not first-visit ([87d3ce4](https://github.com/Favourorg/Stellar-forge/commit/87d3ce41a764067f90f0384ce795f6111fdcaeec)) +- **frontend:** paginate factory event fetch instead of silently capping "all tokens" ([#962](https://github.com/Favourorg/Stellar-forge/issues/962)) ([b480f56](https://github.com/Favourorg/Stellar-forge/commit/b480f56b8f935802aab26d2384efcb3eb3da9080)), closes [#35](https://github.com/Favourorg/Stellar-forge/issues/35) +- **frontend:** pay real base_fee, surface FeeDisplay in mint, block writes on network mismatch ([6d5697d](https://github.com/Favourorg/Stellar-forge/commit/6d5697d3f661be16c4fefccdb1a71f5b5d35734b)) +- **frontend:** remove exhaustive-deps suppressions, fix dep arrays ([a8fcf34](https://github.com/Favourorg/Stellar-forge/commit/a8fcf3463afe36bacf28f5f1f259eb5f8e7ca845)) +- **frontend:** resolve merge fallout — format, getMetadata validation, no-this-alias ([4e0d770](https://github.com/Favourorg/Stellar-forge/commit/4e0d77063f0d8b10f23cc9176ea2217bf9337b08)) +- **frontend:** source FeeDisplay fees from useFactoryState, not the singleton ([e388e7a](https://github.com/Favourorg/Stellar-forge/commit/e388e7aacaf66708e01aba263121bd9b932895b2)) +- **frontend:** stop passing a decimal XLM string to formatXLM ([d23be61](https://github.com/Favourorg/Stellar-forge/commit/d23be616d378af583289ce5544de20673eeb5fda)) +- **frontend:** track Horizon paging_token and pass cursor on load-more ([aa6e15b](https://github.com/Favourorg/Stellar-forge/commit/aa6e15b235bda5842fed1e8aa5848a2e06b04959)) +- **frontend:** unify transaction poll backoff into shared utility ([#960](https://github.com/Favourorg/Stellar-forge/issues/960)) ([2ad85fc](https://github.com/Favourorg/Stellar-forge/commit/2ad85fc7f43c40a66746519eccaf89cb5147e53c)) +- **frontend:** wire orphaned features, fix standalone network, add typecheck gate ([c14d1b1](https://github.com/Favourorg/Stellar-forge/commit/c14d1b108ef210ede1d007f231cd4797f844fe26)) +- **ipfs:** retry image upload on transient Pinata errors ([26a2005](https://github.com/Favourorg/Stellar-forge/commit/26a2005ebfbe5c27c7f132c3f0a031d5c750ac30)), closes [#743](https://github.com/Favourorg/Stellar-forge/issues/743) +- **ipfs:** validate getMetadata response shape before returning ([7183346](https://github.com/Favourorg/Stellar-forge/commit/71833467e8e0aa7c8a770d2905056227e721378c)), closes [#849](https://github.com/Favourorg/Stellar-forge/issues/849) +- make all 202 tests pass ([1043432](https://github.com/Favourorg/Stellar-forge/commit/1043432dcdf6307385661d7261fd8f73bcae6923)) +- pin esbuild/globals devDeps and apply npm audit fixes ([6ccd8c3](https://github.com/Favourorg/Stellar-forge/commit/6ccd8c3418b8617052bd8c290231cabad9d82119)) +- provide VITE_TOKEN_WASM_HASH in E2E CI job ([64c1a5b](https://github.com/Favourorg/Stellar-forge/commit/64c1a5b24f90f4685b1690b8653e620768924240)) +- real bugs surfaced while restoring lint/test coverage ([8434f56](https://github.com/Favourorg/Stellar-forge/commit/8434f5688c3f8877513c5931eef26bf93b85091f)) +- redesign fee transfer and token deployment per issue spec ([e7b8c9e](https://github.com/Favourorg/Stellar-forge/commit/e7b8c9e7f0a77cb618b39afa0b91ea6ac87c5b21)) +- refactor build system, fix contract errors, fix dark mode toggle ([85751f8](https://github.com/Favourorg/Stellar-forge/commit/85751f85239640acbae8197feccb14ff63724c16)) +- **release:** add @actions/io to satisfy @actions/exec's undeclared import ([cd21fdc](https://github.com/Favourorg/Stellar-forge/commit/cd21fdc70110759165e95d85803d48f15dd7225f)) +- **release:** disable husky hooks in the release workflow ([5429060](https://github.com/Favourorg/Stellar-forge/commit/5429060a58cf30265f835f3954a420de043452df)) +- repair local Stellar network startup in E2E CI job ([5aa9026](https://github.com/Favourorg/Stellar-forge/commit/5aa90265077404369cfe81c6a96eb94017075893)) +- replace console.error with logger in CreateToken, TokenForm, MetadataUploadForm ([24805af](https://github.com/Favourorg/Stellar-forge/commit/24805af56b93e60392a4817ba8708c29960dd043)), closes [#848](https://github.com/Favourorg/Stellar-forge/issues/848) +- replace invalid checksum address in validation test ([64ac45a](https://github.com/Favourorg/Stellar-forge/commit/64ac45ae4179ede5aa0fce9533ffaae640ef2084)) +- resolve build failure blocking strict mode verification ([e3370f5](https://github.com/Favourorg/Stellar-forge/commit/e3370f50dec6af5a2780d35d7e11462ecf0c3145)) +- resolve Horizon URL from active network config in useTransactionHistory ([2c25a2d](https://github.com/Favourorg/Stellar-forge/commit/2c25a2d2d3b43a72c5453e84f2e2707b4d443696)), closes [#837](https://github.com/Favourorg/Stellar-forge/issues/837) +- restore ESLint v9 flat config ([a85d008](https://github.com/Favourorg/Stellar-forge/commit/a85d008e18a7f925eff1fd5a7361e624754f28cf)) +- **routing:** fix deep-link for /token/:address and add e2e tests ([1eb308a](https://github.com/Favourorg/Stellar-forge/commit/1eb308ab9014c595c30aa3868e9d3e4b87278470)) +- stop E2E app crash on unknown network and repair Freighter mock ([232afee](https://github.com/Favourorg/Stellar-forge/commit/232afee01997300d0fb64ebbe5101d9c11c520fb)) +- **storybook:** finish the Storybook 10 migration ([a66a453](https://github.com/Favourorg/Stellar-forge/commit/a66a453846c86dd2ee83fcb347380b26af4c66ef)), closes [#893](https://github.com/Favourorg/Stellar-forge/issues/893) +- **token-factory:** enforce strict clippy linting for contract code ([686b143](https://github.com/Favourorg/Stellar-forge/commit/686b143cec68646bffeb75790ac317a450742f1f)) +- **token-factory:** extend reentrancy guard to all state-mutating entrypoints ([#972](https://github.com/Favourorg/Stellar-forge/issues/972)) ([45a1a9c](https://github.com/Favourorg/Stellar-forge/commit/45a1a9c1f077d7dbb4e6989ce6ccf42195e88fce)) +- **token-factory:** reject negative base_fee and metadata_fee ([#973](https://github.com/Favourorg/Stellar-forge/issues/973)) ([e3cdd5e](https://github.com/Favourorg/Stellar-forge/commit/e3cdd5eb5de4962381800beaa58853b45ee4b46d)) +- **token-factory:** store token_wasm_hash in FactoryState ([7de1635](https://github.com/Favourorg/Stellar-forge/commit/7de1635b752553f7166f4e6838620a4dd8d540cc)), closes [#543](https://github.com/Favourorg/Stellar-forge/issues/543) +- **ui:** sanitize and validate token name/symbol inputs ([1e4e2e7](https://github.com/Favourorg/Stellar-forge/commit/1e4e2e74f4f0dec3fa06cd44bc4892e76dd421d7)) +- upgrade soroban-sdk to 25.x and fix wasm build ([1e098e1](https://github.com/Favourorg/Stellar-forge/commit/1e098e149830f6a10e319bd4ac26ef6db8c1c13a)) +- Use correct validation function name in MetadataUploadForm ([b8802cf](https://github.com/Favourorg/Stellar-forge/commit/b8802cfd55f2f9f80e2ec76387c9d91b14bce9e5)) +- use dedicated fee_token for all fee transfers in factory contract ([14db340](https://github.com/Favourorg/Stellar-forge/commit/14db340019273fbbd6538c240d765aba96906ec5)) +- use formatXLM and stroopsToXLM in FeeDisplay and add conversion test ([65b5d94](https://github.com/Favourorg/Stellar-forge/commit/65b5d944ea82d68e68dd816830751533bf58eca2)) +- validate hexToBytes input is exactly 64 hex chars ([4165f9f](https://github.com/Favourorg/Stellar-forge/commit/4165f9f3a9d7285fe3ae50c5784f257c73d77716)), closes [#836](https://github.com/Favourorg/Stellar-forge/issues/836) +- validate token supply before minting to prevent u128 overflow ([#959](https://github.com/Favourorg/Stellar-forge/issues/959)) ([d4027c8](https://github.com/Favourorg/Stellar-forge/commit/d4027c81e69c2d2434374a41e8d2bd514a647c26)), closes [#909](https://github.com/Favourorg/Stellar-forge/issues/909) +- **validation:** use StrKey checksum validation for Stellar addresses ([c55f0f4](https://github.com/Favourorg/Stellar-forge/commit/c55f0f49232a10494906398930488a8eb7e7f9bc)) +- **wallet:** clear all state and token cache on disconnect ([a2b1ed3](https://github.com/Favourorg/Stellar-forge/commit/a2b1ed36c3413c37eca259e389307a2f6f06f556)) ### Features -* **#588:** Build Token Creation Form UI ([b13478c](https://github.com/Favourorg/Stellar-forge/commit/b13478ce4ce5f7f5ff75bd629ee82c8e77c6e00b)), closes [#588](https://github.com/Favourorg/Stellar-forge/issues/588) -* **#589:** Implement StellarService Token Deployment ([b186936](https://github.com/Favourorg/Stellar-forge/commit/b18693646c7a9a6826cae19aef04b6b97fe95e16)), closes [#589](https://github.com/Favourorg/Stellar-forge/issues/589) -* **#590:** Implement IPFS Metadata Upload via Pinata ([98e1fc0](https://github.com/Favourorg/Stellar-forge/commit/98e1fc05522b123fdfba8949d4f891d09ca36315)), closes [#590](https://github.com/Favourorg/Stellar-forge/issues/590) -* **#603:** Create Token Detail Page ([a1aa1ec](https://github.com/Favourorg/Stellar-forge/commit/a1aa1ecd6ccad4ec4e2b00a59e706cff4b133c13)), closes [#603](https://github.com/Favourorg/Stellar-forge/issues/603) -* **#604:** Add React Router for Navigation ([be195b5](https://github.com/Favourorg/Stellar-forge/commit/be195b50249bb8d3cfe632338b279ccbab3078c1)), closes [#604](https://github.com/Favourorg/Stellar-forge/issues/604) -* **#606:** Add loading states and skeleton UI ([41111e0](https://github.com/Favourorg/Stellar-forge/commit/41111e0675574976efd551268375a5f5aafa094e)), closes [#606](https://github.com/Favourorg/Stellar-forge/issues/606) -* **#607:** Add environment variable validation on startup ([5e3ff84](https://github.com/Favourorg/Stellar-forge/commit/5e3ff842dee16505f089da8fa8ddf59ff1cbf0aa)), closes [#607](https://github.com/Favourorg/Stellar-forge/issues/607) -* **#734:** Add debounced search and creator address filter to TokenExplorer ([12c703b](https://github.com/Favourorg/Stellar-forge/commit/12c703bf6f4ef881be1aec3fb7a31659182a05fb)), closes [#734](https://github.com/Favourorg/Stellar-forge/issues/734) -* **#fuzz:** add fuzz targets for set_metadata and mint_tokens ([167432d](https://github.com/Favourorg/Stellar-forge/commit/167432dc36b3a44d2fa2b3bcd891af976dc06ab6)), closes [#fuzz](https://github.com/Favourorg/Stellar-forge/issues/fuzz) -* **a11y:** accessibility audit and fixes ([98eb2f7](https://github.com/Favourorg/Stellar-forge/commit/98eb2f7bce43199095257b3f21b29347db71fb7d)) -* add accessibility improvements (a11y) ([259d1b0](https://github.com/Favourorg/Stellar-forge/commit/259d1b0ba239906605b10feb7a151deea01bb70b)) -* add AddressDisplay component with copy and explorer link ([2ab3bda](https://github.com/Favourorg/Stellar-forge/commit/2ab3bdaa16ba838f6da55e681983df940707cb31)) -* add analytics integration spec and scaffolding ([#522](https://github.com/Favourorg/Stellar-forge/issues/522)) ([e4d8902](https://github.com/Favourorg/Stellar-forge/commit/e4d89029fe13ea8a94a574bc2028f9090bc51cc0)) -* add CHANGELOG.md and PR template with changelog checklist ([89bb67e](https://github.com/Favourorg/Stellar-forge/commit/89bb67ed0b73c25e9a0fad46554b8ee6c35e17cb)) -* add client-side routing with react-router-dom (fixes [#471](https://github.com/Favourorg/Stellar-forge/issues/471)) ([baee94d](https://github.com/Favourorg/Stellar-forge/commit/baee94d5865dea41be3e3a0caa3a70952c8f45b3)) -* add comprehensive error handling system ([62b4348](https://github.com/Favourorg/Stellar-forge/commit/62b43485f363fcdd348e518631221dcdedbca452)) -* add ConfirmModal before all on-chain transactions ([3cef134](https://github.com/Favourorg/Stellar-forge/commit/3cef134598c07ec70c6c8d7ed84549da9a0c6162)) -* add Content-Security-Policy headers ([ef28578](https://github.com/Favourorg/Stellar-forge/commit/ef285786231bd883fab9b5e4f2e369658cb010b4)) -* add contract event history with pagination ([0425f56](https://github.com/Favourorg/Stellar-forge/commit/0425f560eb14fe3ab740e9e1726e045d9259772a)) -* add contract event indexing spec ([#612](https://github.com/Favourorg/Stellar-forge/issues/612)) ([5952c01](https://github.com/Favourorg/Stellar-forge/commit/5952c015de58f01b79a0a3978f7baa09e1ec8c4c)) -* add CopyButton component and integrations [#491](https://github.com/Favourorg/Stellar-forge/issues/491) ([6d16970](https://github.com/Favourorg/Stellar-forge/commit/6d1697051d31d6876a50008a3d7669f69d5315b6)) -* add dark mode support with localStorage persistence ([24e96e5](https://github.com/Favourorg/Stellar-forge/commit/24e96e584e68fdf5177d3631d5172f390ed08465)) -* add dark mode with system preference, localStorage persistence, and toggle button ([5658728](https://github.com/Favourorg/Stellar-forge/commit/5658728f0ba9b5825e3f002c10a8a381c4434ced)) -* add decimals validation for create_token (0-18 inclusive) ([f88ec3c](https://github.com/Favourorg/Stellar-forge/commit/f88ec3c3e3100c34bb383c6b90a92fcb1fd33cc4)), closes [#515](https://github.com/Favourorg/Stellar-forge/issues/515) -* add deploy-contract.sh script for automated contract deployment ([f478eb2](https://github.com/Favourorg/Stellar-forge/commit/f478eb2f264a2ad65366be6217dd897ab5ca1e26)) -* add E2E coverage for network mismatch guard across all write forms Closes [#935](https://github.com/Favourorg/Stellar-forge/issues/935) ([#970](https://github.com/Favourorg/Stellar-forge/issues/970)) ([a644ce6](https://github.com/Favourorg/Stellar-forge/commit/a644ce657163e43308840ecb8e4a5582b7046cf7)) -* add env variable validation and configuration guide ([98642d9](https://github.com/Favourorg/Stellar-forge/commit/98642d9dd07b242b72fa17f7c71c90749209cf71)), closes [#8](https://github.com/Favourorg/Stellar-forge/issues/8) -* add ErrorBoundary component to catch render errors ([d297816](https://github.com/Favourorg/Stellar-forge/commit/d29781600265a3afc90e905556a2b1c995f2dd29)) -* add eslint import order rule spec ([ca4bc6b](https://github.com/Favourorg/Stellar-forge/commit/ca4bc6bad5f926f67845006654a62d413a8d7446)) -* add export CSV functionality to TransactionHistory ([637dc7c](https://github.com/Favourorg/Stellar-forge/commit/637dc7cfdb0c15520196983a6f5a87e0504fe0a1)) -* add fee bump transaction support ([#63](https://github.com/Favourorg/Stellar-forge/issues/63)) ([9b2b8ea](https://github.com/Favourorg/Stellar-forge/commit/9b2b8ea83cad398c574e53d1b5e50876c58252e7)) -* add FeeDisplay component with module-level cache ([e749987](https://github.com/Favourorg/Stellar-forge/commit/e749987653db420fb5261cbe857fb557a697ecd1)) -* add formatTimestamp and timeAgo utilities (#issue) ([02f8f30](https://github.com/Favourorg/Stellar-forge/commit/02f8f308f23c64b660d3419496b21085f9f35059)), closes [#issue](https://github.com/Favourorg/Stellar-forge/issues/issue) -* add formatTokenAmount and parseTokenAmount utilities ([1041ada](https://github.com/Favourorg/Stellar-forge/commit/1041ada734af076be7fd095d40e6c87ab39b58ed)) -* add French (fr) locale i18n support ([4429f89](https://github.com/Favourorg/Stellar-forge/commit/4429f898c5906e2f42b38d3b3069af5acf8b07bd)), closes [#740](https://github.com/Favourorg/Stellar-forge/issues/740) -* add friendbot banner for testnet ([aece4cb](https://github.com/Favourorg/Stellar-forge/commit/aece4cb99d882cf89cd6e87ba8a97312300ead57)) -* add frontend unit tests and fix retry unhandled rejections ([ec4b78b](https://github.com/Favourorg/Stellar-forge/commit/ec4b78b50b9ce92b0c37c64e705b0bd81a0f5f10)), closes [#9](https://github.com/Favourorg/Stellar-forge/issues/9) -* add frontend unit tests for validation utils ([#609](https://github.com/Favourorg/Stellar-forge/issues/609)) ([5ef4995](https://github.com/Favourorg/Stellar-forge/commit/5ef4995f2fce86123490a70b7a320a21ef5cdd19)) -* add get_tokens_by_creator view function ([#38](https://github.com/Favourorg/Stellar-forge/issues/38)) ([17b7ae0](https://github.com/Favourorg/Stellar-forge/commit/17b7ae09f4e8bca9660d61389704a18eab50a42f)) -* add global toast notification system ([ea22272](https://github.com/Favourorg/Stellar-forge/commit/ea22272f16cffdd0390b85ceb56a54fd0fbf519e)) -* Add husky + lint-staged pre-commit hooks ([#59](https://github.com/Favourorg/Stellar-forge/issues/59)) ([b11c468](https://github.com/Favourorg/Stellar-forge/commit/b11c4682e0bf0fbcf4b9885237b135142211c366)) -* add Husky pre-commit and pre-push hooks ([#533](https://github.com/Favourorg/Stellar-forge/issues/533)) ([c232169](https://github.com/Favourorg/Stellar-forge/commit/c232169967c5bcf58d07aeb4885efeed39444ce0)) -* add i18n foundation with react-i18next ([0f8c270](https://github.com/Favourorg/Stellar-forge/commit/0f8c2706990f5b6b6ce9f4c17876efee909929b1)) -* add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/Favourorg/Stellar-forge/issues/33)) ([5ba129f](https://github.com/Favourorg/Stellar-forge/commit/5ba129f8148add491d6dfd406138a3a3ab3a7f1c)) -* add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/Favourorg/Stellar-forge/issues/33)) ([9e76fc4](https://github.com/Favourorg/Stellar-forge/commit/9e76fc48a45c3512ffcc7e9c5edffae81dd0fdf6)) -* Add mainnet deployment checklist modal ([#35](https://github.com/Favourorg/Stellar-forge/issues/35)) ([d3e8f2d](https://github.com/Favourorg/Stellar-forge/commit/d3e8f2dfd04536bc5fede24ca84d1e0d416c8e39)) -* add MetadataAlreadySet guard in set_metadata ([ebbdd65](https://github.com/Favourorg/Stellar-forge/commit/ebbdd65360b829419d112b4dc8544c0396502a65)) -* add MintForm component with address validation and mintTokens service ([ac9df39](https://github.com/Favourorg/Stellar-forge/commit/ac9df395c2e4b4ad710f86211f0ee626e76238e0)) -* add network switching support ([#680](https://github.com/Favourorg/Stellar-forge/issues/680)) ([60e9f3f](https://github.com/Favourorg/Stellar-forge/commit/60e9f3fb185c5be0e93d0763c1ada5c6818ec3f3)) -* add OG tags, react-router-dom, clippy CI, and npm ci ([24d091c](https://github.com/Favourorg/Stellar-forge/commit/24d091c957c65e2b03eb374edfeb9f62c780d969)), closes [#54](https://github.com/Favourorg/Stellar-forge/issues/54) [#56](https://github.com/Favourorg/Stellar-forge/issues/56) [#68](https://github.com/Favourorg/Stellar-forge/issues/68) [#85](https://github.com/Favourorg/Stellar-forge/issues/85) -* add pause/unpause admin function to factory contract ([#39](https://github.com/Favourorg/Stellar-forge/issues/39)) ([5a5c965](https://github.com/Favourorg/Stellar-forge/commit/5a5c9657eb01f741a73fd68b07e8c129c0b72494)) -* add polling, last-updated indicator, and refresh to transaction history ([ac79943](https://github.com/Favourorg/Stellar-forge/commit/ac799436d088dc8a3876b6b1f8f1f3bda7e57e9e)), closes [#752](https://github.com/Favourorg/Stellar-forge/issues/752) -* add Prettier, fix all TS errors, add CI/CD pipeline, add formatAddress and Checkbox UI component ([a11180e](https://github.com/Favourorg/Stellar-forge/commit/a11180e10be6c60a668889a4ca85c4056e65db23)) -* add PWA support with vite-plugin-pwa ([#81](https://github.com/Favourorg/Stellar-forge/issues/81)) ([547110c](https://github.com/Favourorg/Stellar-forge/commit/547110c7a3bf0b9308433e6541a72851315dbc7f)) -* add reentrancy guard to create_token with Error::Reentrancy variant ([986de4b](https://github.com/Favourorg/Stellar-forge/commit/986de4be908dde9aca2df9497827bd4e57c72188)) -* add reusable Modal base component ([#527](https://github.com/Favourorg/Stellar-forge/issues/527)) ([e19c519](https://github.com/Favourorg/Stellar-forge/commit/e19c519d5362139603878ae605d798d0f32d4885)) -* add reusable Modal base component ([#527](https://github.com/Favourorg/Stellar-forge/issues/527)) ([f605b53](https://github.com/Favourorg/Stellar-forge/commit/f605b537b184538356ec3f5dfaf6e77a7023ec68)) -* add robots.txt, sitemap.xml, and meta description for SEO ([de6bb1c](https://github.com/Favourorg/Stellar-forge/commit/de6bb1ca190af7144dbcf42c4e375fb037629e40)) -* add robust useClipboard hook and refactor dashboard ([7149392](https://github.com/Favourorg/Stellar-forge/commit/7149392879177afb4890d27e84fcafd74993380c)), closes [#26](https://github.com/Favourorg/Stellar-forge/issues/26) -* add secure Admin Panel for factory fee management ([39e28a5](https://github.com/Favourorg/Stellar-forge/commit/39e28a5d8ea44f66da35c9103d0283f8ebbca68a)) -* Add security disclosure policy ([#47](https://github.com/Favourorg/Stellar-forge/issues/47)) ([096fcd7](https://github.com/Favourorg/Stellar-forge/commit/096fcd7db59170ab86e51293dfd1c261de5b856c)) -* Add Select UI component with accessibility and dark mode support ([412420a](https://github.com/Favourorg/Stellar-forge/commit/412420aaf6de26d11d299790904564aada4d9982)) -* add semantic release for automated versioning ([bcd42fe](https://github.com/Favourorg/Stellar-forge/commit/bcd42fe4045889bb25e4c751a1999444d91b9e48)) -* add sitemap generation script and update prebuild script to include it ([8948663](https://github.com/Favourorg/Stellar-forge/commit/89486632614de04d357937eebec497dfcd8656bc)) -* add skeleton loaders and a11y improvements ([#475](https://github.com/Favourorg/Stellar-forge/issues/475), [#477](https://github.com/Favourorg/Stellar-forge/issues/477)) ([1ea1e54](https://github.com/Favourorg/Stellar-forge/commit/1ea1e54760f52c844e342691ade1968f9d9f3db4)) -* add skeleton loaders for TokenExplorer and Dashboard ([42867fe](https://github.com/Favourorg/Stellar-forge/commit/42867fe60d0626302ff16fe9f97da65e7ca44aa9)), closes [#735](https://github.com/Favourorg/Stellar-forge/issues/735) -* add skeleton-loaders spec (requirements, design, tasks) ([ec3a9ed](https://github.com/Favourorg/Stellar-forge/commit/ec3a9edccdea9cb861af1c086b32f0e45188e011)) -* add social sharing for newly created tokens ([#521](https://github.com/Favourorg/Stellar-forge/issues/521)) ([7e2cdcc](https://github.com/Favourorg/Stellar-forge/commit/7e2cdcc311980edab824795b7afb3fa37f5bf470)) -* add Soroban benchmark harness for resource cost tracking ([#968](https://github.com/Favourorg/Stellar-forge/issues/968)) ([91b504f](https://github.com/Favourorg/Stellar-forge/commit/91b504f5f459c5e5491cf181a30c00c4611bfb1d)), closes [#12](https://github.com/Favourorg/Stellar-forge/issues/12) -* add soroban-token-sdk audit spec ([ae3686a](https://github.com/Favourorg/Stellar-forge/commit/ae3686a6aa6a9ea90c65cdac09212cbc17484e50)) -* add stellar contract optimize to deployment workflow ([4a56338](https://github.com/Favourorg/Stellar-forge/commit/4a5633820d68a264160311da5c161e36fa3dec9d)) -* add stellarExplorerUrl utility and wire explorer links ([d043699](https://github.com/Favourorg/Stellar-forge/commit/d04369980cab1a6f5a29c557b4857fdec90d0b43)) -* add Storybook stories for ConfirmModal, ProgressIndicator, and InsufficientBalanceWarning ([a25343e](https://github.com/Favourorg/Stellar-forge/commit/a25343ef58f82389e1ee34d6e81304cf0bcba9c8)) -* add Storybook with stories for all UI components ([564a5b8](https://github.com/Favourorg/Stellar-forge/commit/564a5b8747b18cecec42b800a28dd3b4845a51e6)) -* add Terms of Service acceptance modal before first transaction ([#529](https://github.com/Favourorg/Stellar-forge/issues/529)) ([53a7bc8](https://github.com/Favourorg/Stellar-forge/commit/53a7bc8473d5bfc7ddc0b4c8bb6b34d28c6f0b10)) -* add Terms of Service acceptance modal before first transaction ([#529](https://github.com/Favourorg/Stellar-forge/issues/529)) ([b2ddf76](https://github.com/Favourorg/Stellar-forge/commit/b2ddf76f997e7098519c2db85ef732176cc34ecf)) -* add testnet faucet integration via Friendbot ([#519](https://github.com/Favourorg/Stellar-forge/issues/519)) ([f7c2965](https://github.com/Favourorg/Stellar-forge/commit/f7c29653018bc9422437a517de60b021c9d9fd94)) -* add token event history with pagination and event details display ([9196fdf](https://github.com/Favourorg/Stellar-forge/commit/9196fdfa879502ba361811ad750a45319afee0e4)) -* add token search, filter, and sort to Dashboard ([a17250a](https://github.com/Favourorg/Stellar-forge/commit/a17250a7e7415c736f7abfb26c24ad63cce35e51)) -* add token search, filter, and sort to dashboard ([#64](https://github.com/Favourorg/Stellar-forge/issues/64)) ([eb80749](https://github.com/Favourorg/Stellar-forge/commit/eb80749f6deacb0dab54ba40af95e1d1693cdb81)) -* add TokenDashboard with pagination, search, and Explorer links ([d7ce574](https://github.com/Favourorg/Stellar-forge/commit/d7ce574bcb1e0b4670e1cc9c2d895946776aaf1a)) -* add TokenExplorer component with search and pagination ([4b21179](https://github.com/Favourorg/Stellar-forge/commit/4b211798c41fbfb492613f48e66a6bb174a37da1)) -* add TokenMetadata display component ([658efc0](https://github.com/Favourorg/Stellar-forge/commit/658efc0c1321a6b4794c0682e75894e0a45e66aa)) -* Add transaction retry logic with exponential backoff ([#62](https://github.com/Favourorg/Stellar-forge/issues/62)) ([f0d8f02](https://github.com/Favourorg/Stellar-forge/commit/f0d8f02c2d45a8649b21ef2a83f69fc757033bba)) -* Add TransactionHistory component and useTransactionHistory hook for Stellar token operations ([f8fed91](https://github.com/Favourorg/Stellar-forge/commit/f8fed914347008992fae259b506952c2d0c7ae88)) -* Add TransactionStatus component and tests ([4637fb8](https://github.com/Favourorg/Stellar-forge/commit/4637fb8c495482a5609f2f90ea6a5309aa09dd57)) -* add transfer_admin function with tests ([347d54f](https://github.com/Favourorg/Stellar-forge/commit/347d54fbbf885985964f991d51ed4c6807dcd071)) -* add TTL management for all Soroban storage writes ([7b34532](https://github.com/Favourorg/Stellar-forge/commit/7b3453265f83cbc0fe7f0dcaf8a736f21902887c)) -* add UI barrel export and update all imports ([2e4fbe0](https://github.com/Favourorg/Stellar-forge/commit/2e4fbe0e006564fee5c51396ba9137e9de42793c)) -* add update_admin function to token factory contract ([#479](https://github.com/Favourorg/Stellar-forge/issues/479)) ([5db1fe4](https://github.com/Favourorg/Stellar-forge/commit/5db1fe4734dc41788232efd3e11397bf74bd2954)) -* add useDebounce hook, apply to MintForm/BurnForm/Dashboard, fix build ([e8727e1](https://github.com/Favourorg/Stellar-forge/commit/e8727e16b4f1c50beca6977389720fe1497b192b)) -* add useFactoryState hook, coverage thresholds, and CI workflow ([15b366d](https://github.com/Favourorg/Stellar-forge/commit/15b366d315366e901a05351e7d200da9330bd39d)) -* Add useLocalStorage hook and tests ([56eac71](https://github.com/Favourorg/Stellar-forge/commit/56eac719547fd75bdd916da05ab5a8bcde6fc663)) -* add useTokenBalance hook and fix TypeScript errors ([43792b7](https://github.com/Favourorg/Stellar-forge/commit/43792b7593c29fff7929ca1c52e9096b32c4e3ef)) -* add useTokens pagination and useTokenInfo hook ([a473194](https://github.com/Favourorg/Stellar-forge/commit/a473194fbf697aa6feeed853de1253c30d8947df)) -* add VITE_TOKEN_WASM_HASH to env validation and fix duplicate import ([b027cc2](https://github.com/Favourorg/Stellar-forge/commit/b027cc256bc2c3381cedcfab7b48a81805e7f41f)) -* add wallet token portfolio dashboard ([cc28ab9](https://github.com/Favourorg/Stellar-forge/commit/cc28ab9f2d9505077bfbc430aac870983c6979f7)) -* add WalletButton UI component and integrate into App.tsx header ([cf20f69](https://github.com/Favourorg/Stellar-forge/commit/cf20f695cb93d60d96fa4f5f1592f1395ac2ef4f)) -* add wasm-opt post-processing for contract binary ([de1f779](https://github.com/Favourorg/Stellar-forge/commit/de1f779897d4ddbc938d9d1d58e1020d352081a0)) -* add whitelist for fee-free token creation ([59c0f59](https://github.com/Favourorg/Stellar-forge/commit/59c0f598ecfd74fa1cfe5a036a8ac22418e0d823)) -* build token creation form UI on home page ([#667](https://github.com/Favourorg/Stellar-forge/issues/667)) ([0311381](https://github.com/Favourorg/Stellar-forge/commit/03113810e45d1c622661e7b3e6a9d19222d302a1)) -* Burn Tokens UI with danger-zone styling and safety confirmation ([#675](https://github.com/Favourorg/Stellar-forge/issues/675)) ([f894e11](https://github.com/Favourorg/Stellar-forge/commit/f894e116c013786ca1ddd4bce9a7af607a96c418)) -* **burn:** add data-testid attributes for balance display, Max button, and validation error ([0c72f14](https://github.com/Favourorg/Stellar-forge/commit/0c72f141647c5c6b77faca6fbd4ea22c696d4b5e)), closes [#755](https://github.com/Favourorg/Stellar-forge/issues/755) [#755](https://github.com/Favourorg/Stellar-forge/issues/755) -* **ci:** add reproducible WASM hash verification workflow for mainnet deployments ([#950](https://github.com/Favourorg/Stellar-forge/issues/950)) ([abcdbce](https://github.com/Favourorg/Stellar-forge/commit/abcdbceaf28f24c23aaa963bf69c9a0b27b47fd5)), closes [#940](https://github.com/Favourorg/Stellar-forge/issues/940) -* comprehensive contract tests + fix lib.rs compilation errors ([#677](https://github.com/Favourorg/Stellar-forge/issues/677)) ([83a8f8f](https://github.com/Favourorg/Stellar-forge/commit/83a8f8f55ddbdd49046ce8ddb84be53360e16699)) -* **contract:** add batch token creation ([#487](https://github.com/Favourorg/Stellar-forge/issues/487)) ([b50b182](https://github.com/Favourorg/Stellar-forge/commit/b50b18207842a21052d69f1a85c67f893e36231a)) -* **contract:** add optional max supply cap to tokens ([#483](https://github.com/Favourorg/Stellar-forge/issues/483)) ([dc00eb6](https://github.com/Favourorg/Stellar-forge/commit/dc00eb6f44e00cdc437c4824c474cb227837dfef)) -* **contract:** add treasury fee split mechanism ([#485](https://github.com/Favourorg/Stellar-forge/issues/485)) ([d933acf](https://github.com/Favourorg/Stellar-forge/commit/d933acfc8876eb3f0db155a0ec7149d04bc2b323)) -* **contract:** emit events for all state-changing functions ([#482](https://github.com/Favourorg/Stellar-forge/issues/482)) ([0a375a8](https://github.com/Favourorg/Stellar-forge/commit/0a375a8a115d2c580d2c1e801e6936102eba4d19)) -* **contracts:** add schema versioning and implement migrate ([7293485](https://github.com/Favourorg/Stellar-forge/commit/7293485078366ff93f43ebb358360ad335dbde12)) -* **contracts:** add schema versioning and implement migrate ([a9fbd2e](https://github.com/Favourorg/Stellar-forge/commit/a9fbd2e525ce9f459d28cfdbc126c3a50ab68919)) -* create WalletConnectButton component ([766c6b9](https://github.com/Favourorg/Stellar-forge/commit/766c6b92eb995d711458cf20585591120ced5d91)) -* enable TypeScript strict mode ([#531](https://github.com/Favourorg/Stellar-forge/issues/531)) ([bb3ad84](https://github.com/Favourorg/Stellar-forge/commit/bb3ad84b61317ddca30bc365f9eb93d4bfc76b28)) -* enforce u128 for initial_supply and add InvalidTokenParams validation [#517](https://github.com/Favourorg/Stellar-forge/issues/517) ([67582a3](https://github.com/Favourorg/Stellar-forge/commit/67582a37491bb016ab44a09f6539321b776a29d0)) -* enhance security, add contract upgrade support, and integrate E2E tests into CI ([5695ca0](https://github.com/Favourorg/Stellar-forge/commit/5695ca0f03c7e7473d50b32cc8be6ca7c41ea560)) -* enhance token factory with DataKey enum and update storage access ([e0c24c0](https://github.com/Favourorg/Stellar-forge/commit/e0c24c04b0f0a9c6b9ea74afd0778915d2256a6f)) -* **explorer:** add Stellar Expert deep links for accounts, transactions, and contracts ([6d509a4](https://github.com/Favourorg/Stellar-forge/commit/6d509a4719802c15ba7a25454bd1cb63e51f4fdc)) -* extract contract error mapping to contractErrors.ts ([0420e56](https://github.com/Favourorg/Stellar-forge/commit/0420e56d1fa61c2f6923fd51f34e199f9d0aa058)) -* **factory:** add offset/limit pagination to get_tokens_by_creator ([#729](https://github.com/Favourorg/Stellar-forge/issues/729)) ([3f88aae](https://github.com/Favourorg/Stellar-forge/commit/3f88aaeb44917ccbcc07bfa5bb6c8fa8c69f1bec)) -* **frontend:** add ipfs gateway URL resolver and stabilize frontend checks ([005ff3f](https://github.com/Favourorg/Stellar-forge/commit/005ff3f36d8e792c1aae283a908f8e34f4540440)) -* **frontend:** block writes on network mismatch in metadata + admin forms ([#906](https://github.com/Favourorg/Stellar-forge/issues/906)) ([f6e88f3](https://github.com/Favourorg/Stellar-forge/commit/f6e88f390e3f87e5abd34ce35989c5907b83bd98)) -* **frontend:** implement i18n support with es and pt translations ([dcbc1b2](https://github.com/Favourorg/Stellar-forge/commit/dcbc1b2838650f7d285d92ffec61a226f0dd28df)) -* **frontend:** wire network-mismatch banner + FAQ page, drop dead duplicate, fix repo URLs ([901021f](https://github.com/Favourorg/Stellar-forge/commit/901021f9ce8eac98d3d50bf5970006818bd835f8)) -* gate wallet and metadata actions behind ToS ([8318679](https://github.com/Favourorg/Stellar-forge/commit/8318679a05a77d2324ef1032e5a8735df50de38b)) -* global error boundary, toast system, and service error cleanup ([19dbf05](https://github.com/Favourorg/Stellar-forge/commit/19dbf055d8666ad6c29cfb08330d54dba1c37da2)) -* global error boundary, toast system, and service error cleanup ([6ca83ad](https://github.com/Favourorg/Stellar-forge/commit/6ca83ad43e48b722d1decf01505c7df900926b39)) -* **hooks:** add LRU eviction to useTokens module-level cache ([#967](https://github.com/Favourorg/Stellar-forge/issues/967)) ([25ca799](https://github.com/Favourorg/Stellar-forge/commit/25ca799e4b03c97a3d52752f7ccbdda0e0820816)) -* **hooks:** add useTransaction hook for transaction lifecycle ([#489](https://github.com/Favourorg/Stellar-forge/issues/489)) ([18debc3](https://github.com/Favourorg/Stellar-forge/commit/18debc33c6bc0dd55ebb830be061c32663b9b2bd)) -* implement BigInt-safe formatting utilities ([fc30b37](https://github.com/Favourorg/Stellar-forge/commit/fc30b3739e3829c47c164b5fc3ed766a720160e7)) -* implement burn_enabled per-token flag ([7d265e8](https://github.com/Favourorg/Stellar-forge/commit/7d265e844a3490af982d1665e0d6d17287a21ad1)) -* Implement Freighter Wallet Integration ([b91a66e](https://github.com/Favourorg/Stellar-forge/commit/b91a66ea7d8ca5e98b04da98c036bde9103896a8)) -* implement Freighter wallet integration ([#666](https://github.com/Favourorg/Stellar-forge/issues/666)) ([8416cfd](https://github.com/Favourorg/Stellar-forge/commit/8416cfd8dd76863b1142ec6662bd063a5eb5c2c8)) -* implement global error boundary ([#473](https://github.com/Favourorg/Stellar-forge/issues/473)) ([d83fe50](https://github.com/Favourorg/Stellar-forge/commit/d83fe50a891c8e6b0ddf9657f533068d85ae8d9d)) -* implement Horizon API retry logic with exponential backoff and Retry-After handling [#499](https://github.com/Favourorg/Stellar-forge/issues/499) ([cfd31b5](https://github.com/Favourorg/Stellar-forge/commit/cfd31b5b7d3cb95c5a4ac367ed93ec95da884a5f)) -* implement mobile-responsive design for all components ([cfdf285](https://github.com/Favourorg/Stellar-forge/commit/cfdf285acfd73648d3ddb9189c9603994e422016)) -* implement pagination for token dashboard ([#29](https://github.com/Favourorg/Stellar-forge/issues/29)) ([9aa41b1](https://github.com/Favourorg/Stellar-forge/commit/9aa41b1489fc9a4b07d3be68c6f2521197a402f0)) -* implement Pinata IPFS upload service with tests ([6b33365](https://github.com/Favourorg/Stellar-forge/commit/6b33365592b88e4835ff4b0728bfd33fe5c65504)) -* implement Pinata IPFS upload with progress tracking and error handling ([53b3684](https://github.com/Favourorg/Stellar-forge/commit/53b368444cefd75a4ab1ae0ad0856244b78d0d59)) -* implement responsive mobile layout (issue [#616](https://github.com/Favourorg/Stellar-forge/issues/616)) ([49ddf41](https://github.com/Favourorg/Stellar-forge/commit/49ddf41412597f035283a56ce005728838a7bf8e)) -* implement reusable CopyButton component with Clipboard API integration ([2f8b716](https://github.com/Favourorg/Stellar-forge/commit/2f8b71673d4bcfed75cea83aba41ba75c7d39d59)) -* implement Soroban contract invocation logic in StellarService ([3a4af37](https://github.com/Favourorg/Stellar-forge/commit/3a4af37b668bc7dd633dca8f80ab34230a160da8)) -* implement Soroban RPC interactions in stellar.ts ([42c9d18](https://github.com/Favourorg/Stellar-forge/commit/42c9d18240eccc884dcee88d0e56e1897fe2a7de)) -* implement StellarService with full Soroban RPC integration ([3f0a520](https://github.com/Favourorg/Stellar-forge/commit/3f0a52060e1264e34239d59ede6542c9a2791bf6)) -* implement token burn UI and service ([a199523](https://github.com/Favourorg/Stellar-forge/commit/a19952319a4e6efc77ccf128bd72ac0fe6fdc2e3)) -* implement Token Dashboard page ([#673](https://github.com/Favourorg/Stellar-forge/issues/673)) ([c3b204c](https://github.com/Favourorg/Stellar-forge/commit/c3b204c15fcca7827fd91c69f97cc0708395e3a8)) -* implement token detail page ([a79ef19](https://github.com/Favourorg/Stellar-forge/commit/a79ef19b62d87c742306511e4c6d4194f47f4301)) -* implement TokenDashboard page with TokenCard component and index-based pagination ([4af373b](https://github.com/Favourorg/Stellar-forge/commit/4af373b0d6ae3928d8c9f09f6fec2e181c1fd857)) -* implement TokenDetail page ([#470](https://github.com/Favourorg/Stellar-forge/issues/470)) ([71ca751](https://github.com/Favourorg/Stellar-forge/commit/71ca75186290f61636b5217b0e4817d8d70d5860)) -* implement TokenDetail page with IPFS metadata, mint/burn/set-metadata inline forms, and 404 state ([9c7f0eb](https://github.com/Favourorg/Stellar-forge/commit/9c7f0eb21f1218f5ad84e0026eb007b6760fcf49)) -* implement transaction status tracking ([#681](https://github.com/Favourorg/Stellar-forge/issues/681)) ([3c0a793](https://github.com/Favourorg/Stellar-forge/commit/3c0a79320128a7e0ebe31f2c6c2091dedbabc790)) -* implement update_treasury in token-factory ([0c381d3](https://github.com/Favourorg/Stellar-forge/commit/0c381d364fc58b048d6ac3b5a3c8e2fdb014a4d4)) -* implement useLocalStorage for dark mode context and add tests for useDarkMode hook ([f04664c](https://github.com/Favourorg/Stellar-forge/commit/f04664cf78bf2f23ca284ae6d8f7807432928a30)) -* implement useLocalStorage hook and integrate for Dark Mode, Network, and Language [#518](https://github.com/Favourorg/Stellar-forge/issues/518) ([9a25f84](https://github.com/Favourorg/Stellar-forge/commit/9a25f843fb0e4aa8c1cd12c84a1e045243386228)) -* implement useTokens hook with parallel fetching and cache ([d9cc12d](https://github.com/Favourorg/Stellar-forge/commit/d9cc12d47d2b1f03c90a062a7a4c43e5a8b9d16f)), closes [#16](https://github.com/Favourorg/Stellar-forge/issues/16) -* implement wallet auto-reconnect and Freighter event listeners ([4cba9dc](https://github.com/Favourorg/Stellar-forge/commit/4cba9dc763125c9a8fa920a14aa94eb91f241835)) -* integrate Sentry error tracking for failed contract calls ([e0cb9f9](https://github.com/Favourorg/Stellar-forge/commit/e0cb9f995c7d04606937ca8c1df0cd923e71c96d)), closes [#757](https://github.com/Favourorg/Stellar-forge/issues/757) -* **ipfs:** implement IPFS metadata upload via Pinata ([#669](https://github.com/Favourorg/Stellar-forge/issues/669)) ([949bcc3](https://github.com/Favourorg/Stellar-forge/commit/949bcc3dc44b247c9fc084edd83cac814a510dd2)) -* Mint Tokens UI with RHF validation and token dropdown ([#674](https://github.com/Favourorg/Stellar-forge/issues/674)) ([223235d](https://github.com/Favourorg/Stellar-forge/commit/223235d8b6d6995d04610e0103b44853d267c4f4)) -* mobile responsive design ([90814c2](https://github.com/Favourorg/Stellar-forge/commit/90814c291d43fc2cc5cb1082eaedb49d70b8f228)) -* **monitoring:** add monitoring docs and sentry dependency ([e043a5c](https://github.com/Favourorg/Stellar-forge/commit/e043a5c4778490cdc5f61a5a6a8bec84f04a97e0)) -* **monitoring:** add Sentry, uptime monitoring, and health endpoint ([cee6369](https://github.com/Favourorg/Stellar-forge/commit/cee6369984c5aa792f631cb2d99f5387f523a675)) -* move wallet state to global React Context ([6c24340](https://github.com/Favourorg/Stellar-forge/commit/6c243409493ecaf75dcaf7020b07e51fa764489e)) -* network switcher with mainnet warning and localStorage persistence ([5fa8531](https://github.com/Favourorg/Stellar-forge/commit/5fa8531fe7735ea781dfdcc3d0393e43b2392138)) -* pause/unpause factory already implemented; add burn-while-paused test ([#480](https://github.com/Favourorg/Stellar-forge/issues/480)) ([4dd54ca](https://github.com/Favourorg/Stellar-forge/commit/4dd54cae186d0f659b02c09174ef52b8c45d40bd)) -* provide services via StellarContext, re-init on network change ([4f924de](https://github.com/Favourorg/Stellar-forge/commit/4f924de5f21060928b716c73263e9dde08eb6232)) -* **security:** add Content Security Policy and security headers ([19f0f1f](https://github.com/Favourorg/Stellar-forge/commit/19f0f1f1a414ff3aaa40c7d880892ae53d0fb494)) -* **security:** add dependency audit and Dependabot configuration ([9f404c1](https://github.com/Favourorg/Stellar-forge/commit/9f404c125b296e2693acefd67f2e6c0c1476f987)), closes [hi#severity](https://github.com/hi/issues/severity) [#502](https://github.com/Favourorg/Stellar-forge/issues/502) -* **security:** add strict CSP, X-Frame-Options, and X-Content-Type-Options headers ([a625191](https://github.com/Favourorg/Stellar-forge/commit/a625191242ad136c2f085d1524916a0781bbc0ea)) -* show XLM/USD equivalent in FeeDisplay component ([fd3c20d](https://github.com/Favourorg/Stellar-forge/commit/fd3c20d6172b5f12542e4822efc0e193e64b9f37)), closes [#733](https://github.com/Favourorg/Stellar-forge/issues/733) -* toast notification system already implemented ([#474](https://github.com/Favourorg/Stellar-forge/issues/474)) ([73b04c9](https://github.com/Favourorg/Stellar-forge/commit/73b04c93422a042df4c9343a024b0d799f062b65)) -* **token-factory:** validate create_token params and use InvalidParameters error ([4e7abc4](https://github.com/Favourorg/Stellar-forge/commit/4e7abc445ef9bb859033a1154087f4e06c60d426)) -* **ui:** add DropZone drag-and-drop component and replace file input in MetadataUploadForm ([fee9791](https://github.com/Favourorg/Stellar-forge/commit/fee979106b6aa2f6cabdae7a8d89e34187fb4516)) -* **ui:** add network-aware Stellar Expert explorer links ([20dced8](https://github.com/Favourorg/Stellar-forge/commit/20dced85535f61c3700295b38486148e21fcee85)), closes [#621](https://github.com/Favourorg/Stellar-forge/issues/621) -* **ui:** confirmation modal before every state-changing transaction ([#490](https://github.com/Favourorg/Stellar-forge/issues/490)) ([88291e3](https://github.com/Favourorg/Stellar-forge/commit/88291e3a54fb6581068f0aa474301effc8d5839f)) -* **ui:** implement MetadataForm with IPFS upload + Stellar linking ([#676](https://github.com/Favourorg/Stellar-forge/issues/676)) ([20f5327](https://github.com/Favourorg/Stellar-forge/commit/20f53270a24aafadba31984dde41b3b1f4605ad7)) -* upgrade mechanism, ADRs, QR code sharing, onboarding tutorial ([7b59535](https://github.com/Favourorg/Stellar-forge/commit/7b5953553e50e0d011aefd8d581d346cd03eef0d)), closes [#1](https://github.com/Favourorg/Stellar-forge/issues/1) [#2](https://github.com/Favourorg/Stellar-forge/issues/2) [#3](https://github.com/Favourorg/Stellar-forge/issues/3) [#4](https://github.com/Favourorg/Stellar-forge/issues/4) -* **ux:** insufficient balance warning before transaction submission ([#496](https://github.com/Favourorg/Stellar-forge/issues/496)) ([0777d93](https://github.com/Favourorg/Stellar-forge/commit/0777d937bf16c0428cc0c9b8981bcf6322cfba66)) -* wire setMetadata to StellarService in TokenDetail ([04de946](https://github.com/Favourorg/Stellar-forge/commit/04de946b9f1be0b11b385f12dd0138798cb79437)) -* wire up mint and burn token UI to contract ([ca6b7b4](https://github.com/Favourorg/Stellar-forge/commit/ca6b7b41537ff00ac62d56316089355f62a6b188)), closes [#541](https://github.com/Favourorg/Stellar-forge/issues/541) - +- **#588:** Build Token Creation Form UI ([b13478c](https://github.com/Favourorg/Stellar-forge/commit/b13478ce4ce5f7f5ff75bd629ee82c8e77c6e00b)), closes [#588](https://github.com/Favourorg/Stellar-forge/issues/588) +- **#589:** Implement StellarService Token Deployment ([b186936](https://github.com/Favourorg/Stellar-forge/commit/b18693646c7a9a6826cae19aef04b6b97fe95e16)), closes [#589](https://github.com/Favourorg/Stellar-forge/issues/589) +- **#590:** Implement IPFS Metadata Upload via Pinata ([98e1fc0](https://github.com/Favourorg/Stellar-forge/commit/98e1fc05522b123fdfba8949d4f891d09ca36315)), closes [#590](https://github.com/Favourorg/Stellar-forge/issues/590) +- **#603:** Create Token Detail Page ([a1aa1ec](https://github.com/Favourorg/Stellar-forge/commit/a1aa1ecd6ccad4ec4e2b00a59e706cff4b133c13)), closes [#603](https://github.com/Favourorg/Stellar-forge/issues/603) +- **#604:** Add React Router for Navigation ([be195b5](https://github.com/Favourorg/Stellar-forge/commit/be195b50249bb8d3cfe632338b279ccbab3078c1)), closes [#604](https://github.com/Favourorg/Stellar-forge/issues/604) +- **#606:** Add loading states and skeleton UI ([41111e0](https://github.com/Favourorg/Stellar-forge/commit/41111e0675574976efd551268375a5f5aafa094e)), closes [#606](https://github.com/Favourorg/Stellar-forge/issues/606) +- **#607:** Add environment variable validation on startup ([5e3ff84](https://github.com/Favourorg/Stellar-forge/commit/5e3ff842dee16505f089da8fa8ddf59ff1cbf0aa)), closes [#607](https://github.com/Favourorg/Stellar-forge/issues/607) +- **#734:** Add debounced search and creator address filter to TokenExplorer ([12c703b](https://github.com/Favourorg/Stellar-forge/commit/12c703bf6f4ef881be1aec3fb7a31659182a05fb)), closes [#734](https://github.com/Favourorg/Stellar-forge/issues/734) +- **#fuzz:** add fuzz targets for set_metadata and mint_tokens ([167432d](https://github.com/Favourorg/Stellar-forge/commit/167432dc36b3a44d2fa2b3bcd891af976dc06ab6)), closes [#fuzz](https://github.com/Favourorg/Stellar-forge/issues/fuzz) +- **a11y:** accessibility audit and fixes ([98eb2f7](https://github.com/Favourorg/Stellar-forge/commit/98eb2f7bce43199095257b3f21b29347db71fb7d)) +- add accessibility improvements (a11y) ([259d1b0](https://github.com/Favourorg/Stellar-forge/commit/259d1b0ba239906605b10feb7a151deea01bb70b)) +- add AddressDisplay component with copy and explorer link ([2ab3bda](https://github.com/Favourorg/Stellar-forge/commit/2ab3bdaa16ba838f6da55e681983df940707cb31)) +- add analytics integration spec and scaffolding ([#522](https://github.com/Favourorg/Stellar-forge/issues/522)) ([e4d8902](https://github.com/Favourorg/Stellar-forge/commit/e4d89029fe13ea8a94a574bc2028f9090bc51cc0)) +- add CHANGELOG.md and PR template with changelog checklist ([89bb67e](https://github.com/Favourorg/Stellar-forge/commit/89bb67ed0b73c25e9a0fad46554b8ee6c35e17cb)) +- add client-side routing with react-router-dom (fixes [#471](https://github.com/Favourorg/Stellar-forge/issues/471)) ([baee94d](https://github.com/Favourorg/Stellar-forge/commit/baee94d5865dea41be3e3a0caa3a70952c8f45b3)) +- add comprehensive error handling system ([62b4348](https://github.com/Favourorg/Stellar-forge/commit/62b43485f363fcdd348e518631221dcdedbca452)) +- add ConfirmModal before all on-chain transactions ([3cef134](https://github.com/Favourorg/Stellar-forge/commit/3cef134598c07ec70c6c8d7ed84549da9a0c6162)) +- add Content-Security-Policy headers ([ef28578](https://github.com/Favourorg/Stellar-forge/commit/ef285786231bd883fab9b5e4f2e369658cb010b4)) +- add contract event history with pagination ([0425f56](https://github.com/Favourorg/Stellar-forge/commit/0425f560eb14fe3ab740e9e1726e045d9259772a)) +- add contract event indexing spec ([#612](https://github.com/Favourorg/Stellar-forge/issues/612)) ([5952c01](https://github.com/Favourorg/Stellar-forge/commit/5952c015de58f01b79a0a3978f7baa09e1ec8c4c)) +- add CopyButton component and integrations [#491](https://github.com/Favourorg/Stellar-forge/issues/491) ([6d16970](https://github.com/Favourorg/Stellar-forge/commit/6d1697051d31d6876a50008a3d7669f69d5315b6)) +- add dark mode support with localStorage persistence ([24e96e5](https://github.com/Favourorg/Stellar-forge/commit/24e96e584e68fdf5177d3631d5172f390ed08465)) +- add dark mode with system preference, localStorage persistence, and toggle button ([5658728](https://github.com/Favourorg/Stellar-forge/commit/5658728f0ba9b5825e3f002c10a8a381c4434ced)) +- add decimals validation for create_token (0-18 inclusive) ([f88ec3c](https://github.com/Favourorg/Stellar-forge/commit/f88ec3c3e3100c34bb383c6b90a92fcb1fd33cc4)), closes [#515](https://github.com/Favourorg/Stellar-forge/issues/515) +- add deploy-contract.sh script for automated contract deployment ([f478eb2](https://github.com/Favourorg/Stellar-forge/commit/f478eb2f264a2ad65366be6217dd897ab5ca1e26)) +- add E2E coverage for network mismatch guard across all write forms Closes [#935](https://github.com/Favourorg/Stellar-forge/issues/935) ([#970](https://github.com/Favourorg/Stellar-forge/issues/970)) ([a644ce6](https://github.com/Favourorg/Stellar-forge/commit/a644ce657163e43308840ecb8e4a5582b7046cf7)) +- add env variable validation and configuration guide ([98642d9](https://github.com/Favourorg/Stellar-forge/commit/98642d9dd07b242b72fa17f7c71c90749209cf71)), closes [#8](https://github.com/Favourorg/Stellar-forge/issues/8) +- add ErrorBoundary component to catch render errors ([d297816](https://github.com/Favourorg/Stellar-forge/commit/d29781600265a3afc90e905556a2b1c995f2dd29)) +- add eslint import order rule spec ([ca4bc6b](https://github.com/Favourorg/Stellar-forge/commit/ca4bc6bad5f926f67845006654a62d413a8d7446)) +- add export CSV functionality to TransactionHistory ([637dc7c](https://github.com/Favourorg/Stellar-forge/commit/637dc7cfdb0c15520196983a6f5a87e0504fe0a1)) +- add fee bump transaction support ([#63](https://github.com/Favourorg/Stellar-forge/issues/63)) ([9b2b8ea](https://github.com/Favourorg/Stellar-forge/commit/9b2b8ea83cad398c574e53d1b5e50876c58252e7)) +- add FeeDisplay component with module-level cache ([e749987](https://github.com/Favourorg/Stellar-forge/commit/e749987653db420fb5261cbe857fb557a697ecd1)) +- add formatTimestamp and timeAgo utilities (#issue) ([02f8f30](https://github.com/Favourorg/Stellar-forge/commit/02f8f308f23c64b660d3419496b21085f9f35059)), closes [#issue](https://github.com/Favourorg/Stellar-forge/issues/issue) +- add formatTokenAmount and parseTokenAmount utilities ([1041ada](https://github.com/Favourorg/Stellar-forge/commit/1041ada734af076be7fd095d40e6c87ab39b58ed)) +- add French (fr) locale i18n support ([4429f89](https://github.com/Favourorg/Stellar-forge/commit/4429f898c5906e2f42b38d3b3069af5acf8b07bd)), closes [#740](https://github.com/Favourorg/Stellar-forge/issues/740) +- add friendbot banner for testnet ([aece4cb](https://github.com/Favourorg/Stellar-forge/commit/aece4cb99d882cf89cd6e87ba8a97312300ead57)) +- add frontend unit tests and fix retry unhandled rejections ([ec4b78b](https://github.com/Favourorg/Stellar-forge/commit/ec4b78b50b9ce92b0c37c64e705b0bd81a0f5f10)), closes [#9](https://github.com/Favourorg/Stellar-forge/issues/9) +- add frontend unit tests for validation utils ([#609](https://github.com/Favourorg/Stellar-forge/issues/609)) ([5ef4995](https://github.com/Favourorg/Stellar-forge/commit/5ef4995f2fce86123490a70b7a320a21ef5cdd19)) +- add get_tokens_by_creator view function ([#38](https://github.com/Favourorg/Stellar-forge/issues/38)) ([17b7ae0](https://github.com/Favourorg/Stellar-forge/commit/17b7ae09f4e8bca9660d61389704a18eab50a42f)) +- add global toast notification system ([ea22272](https://github.com/Favourorg/Stellar-forge/commit/ea22272f16cffdd0390b85ceb56a54fd0fbf519e)) +- Add husky + lint-staged pre-commit hooks ([#59](https://github.com/Favourorg/Stellar-forge/issues/59)) ([b11c468](https://github.com/Favourorg/Stellar-forge/commit/b11c4682e0bf0fbcf4b9885237b135142211c366)) +- add Husky pre-commit and pre-push hooks ([#533](https://github.com/Favourorg/Stellar-forge/issues/533)) ([c232169](https://github.com/Favourorg/Stellar-forge/commit/c232169967c5bcf58d07aeb4885efeed39444ce0)) +- add i18n foundation with react-i18next ([0f8c270](https://github.com/Favourorg/Stellar-forge/commit/0f8c2706990f5b6b6ce9f4c17876efee909929b1)) +- add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/Favourorg/Stellar-forge/issues/33)) ([5ba129f](https://github.com/Favourorg/Stellar-forge/commit/5ba129f8148add491d6dfd406138a3a3ab3a7f1c)) +- add isValidIPFSUri validation utility and SetMetadataForm ([#33](https://github.com/Favourorg/Stellar-forge/issues/33)) ([9e76fc4](https://github.com/Favourorg/Stellar-forge/commit/9e76fc48a45c3512ffcc7e9c5edffae81dd0fdf6)) +- Add mainnet deployment checklist modal ([#35](https://github.com/Favourorg/Stellar-forge/issues/35)) ([d3e8f2d](https://github.com/Favourorg/Stellar-forge/commit/d3e8f2dfd04536bc5fede24ca84d1e0d416c8e39)) +- add MetadataAlreadySet guard in set_metadata ([ebbdd65](https://github.com/Favourorg/Stellar-forge/commit/ebbdd65360b829419d112b4dc8544c0396502a65)) +- add MintForm component with address validation and mintTokens service ([ac9df39](https://github.com/Favourorg/Stellar-forge/commit/ac9df395c2e4b4ad710f86211f0ee626e76238e0)) +- add network switching support ([#680](https://github.com/Favourorg/Stellar-forge/issues/680)) ([60e9f3f](https://github.com/Favourorg/Stellar-forge/commit/60e9f3fb185c5be0e93d0763c1ada5c6818ec3f3)) +- add OG tags, react-router-dom, clippy CI, and npm ci ([24d091c](https://github.com/Favourorg/Stellar-forge/commit/24d091c957c65e2b03eb374edfeb9f62c780d969)), closes [#54](https://github.com/Favourorg/Stellar-forge/issues/54) [#56](https://github.com/Favourorg/Stellar-forge/issues/56) [#68](https://github.com/Favourorg/Stellar-forge/issues/68) [#85](https://github.com/Favourorg/Stellar-forge/issues/85) +- add pause/unpause admin function to factory contract ([#39](https://github.com/Favourorg/Stellar-forge/issues/39)) ([5a5c965](https://github.com/Favourorg/Stellar-forge/commit/5a5c9657eb01f741a73fd68b07e8c129c0b72494)) +- add polling, last-updated indicator, and refresh to transaction history ([ac79943](https://github.com/Favourorg/Stellar-forge/commit/ac799436d088dc8a3876b6b1f8f1f3bda7e57e9e)), closes [#752](https://github.com/Favourorg/Stellar-forge/issues/752) +- add Prettier, fix all TS errors, add CI/CD pipeline, add formatAddress and Checkbox UI component ([a11180e](https://github.com/Favourorg/Stellar-forge/commit/a11180e10be6c60a668889a4ca85c4056e65db23)) +- add PWA support with vite-plugin-pwa ([#81](https://github.com/Favourorg/Stellar-forge/issues/81)) ([547110c](https://github.com/Favourorg/Stellar-forge/commit/547110c7a3bf0b9308433e6541a72851315dbc7f)) +- add reentrancy guard to create_token with Error::Reentrancy variant ([986de4b](https://github.com/Favourorg/Stellar-forge/commit/986de4be908dde9aca2df9497827bd4e57c72188)) +- add reusable Modal base component ([#527](https://github.com/Favourorg/Stellar-forge/issues/527)) ([e19c519](https://github.com/Favourorg/Stellar-forge/commit/e19c519d5362139603878ae605d798d0f32d4885)) +- add reusable Modal base component ([#527](https://github.com/Favourorg/Stellar-forge/issues/527)) ([f605b53](https://github.com/Favourorg/Stellar-forge/commit/f605b537b184538356ec3f5dfaf6e77a7023ec68)) +- add robots.txt, sitemap.xml, and meta description for SEO ([de6bb1c](https://github.com/Favourorg/Stellar-forge/commit/de6bb1ca190af7144dbcf42c4e375fb037629e40)) +- add robust useClipboard hook and refactor dashboard ([7149392](https://github.com/Favourorg/Stellar-forge/commit/7149392879177afb4890d27e84fcafd74993380c)), closes [#26](https://github.com/Favourorg/Stellar-forge/issues/26) +- add secure Admin Panel for factory fee management ([39e28a5](https://github.com/Favourorg/Stellar-forge/commit/39e28a5d8ea44f66da35c9103d0283f8ebbca68a)) +- Add security disclosure policy ([#47](https://github.com/Favourorg/Stellar-forge/issues/47)) ([096fcd7](https://github.com/Favourorg/Stellar-forge/commit/096fcd7db59170ab86e51293dfd1c261de5b856c)) +- Add Select UI component with accessibility and dark mode support ([412420a](https://github.com/Favourorg/Stellar-forge/commit/412420aaf6de26d11d299790904564aada4d9982)) +- add semantic release for automated versioning ([bcd42fe](https://github.com/Favourorg/Stellar-forge/commit/bcd42fe4045889bb25e4c751a1999444d91b9e48)) +- add sitemap generation script and update prebuild script to include it ([8948663](https://github.com/Favourorg/Stellar-forge/commit/89486632614de04d357937eebec497dfcd8656bc)) +- add skeleton loaders and a11y improvements ([#475](https://github.com/Favourorg/Stellar-forge/issues/475), [#477](https://github.com/Favourorg/Stellar-forge/issues/477)) ([1ea1e54](https://github.com/Favourorg/Stellar-forge/commit/1ea1e54760f52c844e342691ade1968f9d9f3db4)) +- add skeleton loaders for TokenExplorer and Dashboard ([42867fe](https://github.com/Favourorg/Stellar-forge/commit/42867fe60d0626302ff16fe9f97da65e7ca44aa9)), closes [#735](https://github.com/Favourorg/Stellar-forge/issues/735) +- add skeleton-loaders spec (requirements, design, tasks) ([ec3a9ed](https://github.com/Favourorg/Stellar-forge/commit/ec3a9edccdea9cb861af1c086b32f0e45188e011)) +- add social sharing for newly created tokens ([#521](https://github.com/Favourorg/Stellar-forge/issues/521)) ([7e2cdcc](https://github.com/Favourorg/Stellar-forge/commit/7e2cdcc311980edab824795b7afb3fa37f5bf470)) +- add Soroban benchmark harness for resource cost tracking ([#968](https://github.com/Favourorg/Stellar-forge/issues/968)) ([91b504f](https://github.com/Favourorg/Stellar-forge/commit/91b504f5f459c5e5491cf181a30c00c4611bfb1d)), closes [#12](https://github.com/Favourorg/Stellar-forge/issues/12) +- add soroban-token-sdk audit spec ([ae3686a](https://github.com/Favourorg/Stellar-forge/commit/ae3686a6aa6a9ea90c65cdac09212cbc17484e50)) +- add stellar contract optimize to deployment workflow ([4a56338](https://github.com/Favourorg/Stellar-forge/commit/4a5633820d68a264160311da5c161e36fa3dec9d)) +- add stellarExplorerUrl utility and wire explorer links ([d043699](https://github.com/Favourorg/Stellar-forge/commit/d04369980cab1a6f5a29c557b4857fdec90d0b43)) +- add Storybook stories for ConfirmModal, ProgressIndicator, and InsufficientBalanceWarning ([a25343e](https://github.com/Favourorg/Stellar-forge/commit/a25343ef58f82389e1ee34d6e81304cf0bcba9c8)) +- add Storybook with stories for all UI components ([564a5b8](https://github.com/Favourorg/Stellar-forge/commit/564a5b8747b18cecec42b800a28dd3b4845a51e6)) +- add Terms of Service acceptance modal before first transaction ([#529](https://github.com/Favourorg/Stellar-forge/issues/529)) ([53a7bc8](https://github.com/Favourorg/Stellar-forge/commit/53a7bc8473d5bfc7ddc0b4c8bb6b34d28c6f0b10)) +- add Terms of Service acceptance modal before first transaction ([#529](https://github.com/Favourorg/Stellar-forge/issues/529)) ([b2ddf76](https://github.com/Favourorg/Stellar-forge/commit/b2ddf76f997e7098519c2db85ef732176cc34ecf)) +- add testnet faucet integration via Friendbot ([#519](https://github.com/Favourorg/Stellar-forge/issues/519)) ([f7c2965](https://github.com/Favourorg/Stellar-forge/commit/f7c29653018bc9422437a517de60b021c9d9fd94)) +- add token event history with pagination and event details display ([9196fdf](https://github.com/Favourorg/Stellar-forge/commit/9196fdfa879502ba361811ad750a45319afee0e4)) +- add token search, filter, and sort to Dashboard ([a17250a](https://github.com/Favourorg/Stellar-forge/commit/a17250a7e7415c736f7abfb26c24ad63cce35e51)) +- add token search, filter, and sort to dashboard ([#64](https://github.com/Favourorg/Stellar-forge/issues/64)) ([eb80749](https://github.com/Favourorg/Stellar-forge/commit/eb80749f6deacb0dab54ba40af95e1d1693cdb81)) +- add TokenDashboard with pagination, search, and Explorer links ([d7ce574](https://github.com/Favourorg/Stellar-forge/commit/d7ce574bcb1e0b4670e1cc9c2d895946776aaf1a)) +- add TokenExplorer component with search and pagination ([4b21179](https://github.com/Favourorg/Stellar-forge/commit/4b211798c41fbfb492613f48e66a6bb174a37da1)) +- add TokenMetadata display component ([658efc0](https://github.com/Favourorg/Stellar-forge/commit/658efc0c1321a6b4794c0682e75894e0a45e66aa)) +- Add transaction retry logic with exponential backoff ([#62](https://github.com/Favourorg/Stellar-forge/issues/62)) ([f0d8f02](https://github.com/Favourorg/Stellar-forge/commit/f0d8f02c2d45a8649b21ef2a83f69fc757033bba)) +- Add TransactionHistory component and useTransactionHistory hook for Stellar token operations ([f8fed91](https://github.com/Favourorg/Stellar-forge/commit/f8fed914347008992fae259b506952c2d0c7ae88)) +- Add TransactionStatus component and tests ([4637fb8](https://github.com/Favourorg/Stellar-forge/commit/4637fb8c495482a5609f2f90ea6a5309aa09dd57)) +- add transfer_admin function with tests ([347d54f](https://github.com/Favourorg/Stellar-forge/commit/347d54fbbf885985964f991d51ed4c6807dcd071)) +- add TTL management for all Soroban storage writes ([7b34532](https://github.com/Favourorg/Stellar-forge/commit/7b3453265f83cbc0fe7f0dcaf8a736f21902887c)) +- add UI barrel export and update all imports ([2e4fbe0](https://github.com/Favourorg/Stellar-forge/commit/2e4fbe0e006564fee5c51396ba9137e9de42793c)) +- add update_admin function to token factory contract ([#479](https://github.com/Favourorg/Stellar-forge/issues/479)) ([5db1fe4](https://github.com/Favourorg/Stellar-forge/commit/5db1fe4734dc41788232efd3e11397bf74bd2954)) +- add useDebounce hook, apply to MintForm/BurnForm/Dashboard, fix build ([e8727e1](https://github.com/Favourorg/Stellar-forge/commit/e8727e16b4f1c50beca6977389720fe1497b192b)) +- add useFactoryState hook, coverage thresholds, and CI workflow ([15b366d](https://github.com/Favourorg/Stellar-forge/commit/15b366d315366e901a05351e7d200da9330bd39d)) +- Add useLocalStorage hook and tests ([56eac71](https://github.com/Favourorg/Stellar-forge/commit/56eac719547fd75bdd916da05ab5a8bcde6fc663)) +- add useTokenBalance hook and fix TypeScript errors ([43792b7](https://github.com/Favourorg/Stellar-forge/commit/43792b7593c29fff7929ca1c52e9096b32c4e3ef)) +- add useTokens pagination and useTokenInfo hook ([a473194](https://github.com/Favourorg/Stellar-forge/commit/a473194fbf697aa6feeed853de1253c30d8947df)) +- add VITE_TOKEN_WASM_HASH to env validation and fix duplicate import ([b027cc2](https://github.com/Favourorg/Stellar-forge/commit/b027cc256bc2c3381cedcfab7b48a81805e7f41f)) +- add wallet token portfolio dashboard ([cc28ab9](https://github.com/Favourorg/Stellar-forge/commit/cc28ab9f2d9505077bfbc430aac870983c6979f7)) +- add WalletButton UI component and integrate into App.tsx header ([cf20f69](https://github.com/Favourorg/Stellar-forge/commit/cf20f695cb93d60d96fa4f5f1592f1395ac2ef4f)) +- add wasm-opt post-processing for contract binary ([de1f779](https://github.com/Favourorg/Stellar-forge/commit/de1f779897d4ddbc938d9d1d58e1020d352081a0)) +- add whitelist for fee-free token creation ([59c0f59](https://github.com/Favourorg/Stellar-forge/commit/59c0f598ecfd74fa1cfe5a036a8ac22418e0d823)) +- build token creation form UI on home page ([#667](https://github.com/Favourorg/Stellar-forge/issues/667)) ([0311381](https://github.com/Favourorg/Stellar-forge/commit/03113810e45d1c622661e7b3e6a9d19222d302a1)) +- Burn Tokens UI with danger-zone styling and safety confirmation ([#675](https://github.com/Favourorg/Stellar-forge/issues/675)) ([f894e11](https://github.com/Favourorg/Stellar-forge/commit/f894e116c013786ca1ddd4bce9a7af607a96c418)) +- **burn:** add data-testid attributes for balance display, Max button, and validation error ([0c72f14](https://github.com/Favourorg/Stellar-forge/commit/0c72f141647c5c6b77faca6fbd4ea22c696d4b5e)), closes [#755](https://github.com/Favourorg/Stellar-forge/issues/755) [#755](https://github.com/Favourorg/Stellar-forge/issues/755) +- **ci:** add reproducible WASM hash verification workflow for mainnet deployments ([#950](https://github.com/Favourorg/Stellar-forge/issues/950)) ([abcdbce](https://github.com/Favourorg/Stellar-forge/commit/abcdbceaf28f24c23aaa963bf69c9a0b27b47fd5)), closes [#940](https://github.com/Favourorg/Stellar-forge/issues/940) +- comprehensive contract tests + fix lib.rs compilation errors ([#677](https://github.com/Favourorg/Stellar-forge/issues/677)) ([83a8f8f](https://github.com/Favourorg/Stellar-forge/commit/83a8f8f55ddbdd49046ce8ddb84be53360e16699)) +- **contract:** add batch token creation ([#487](https://github.com/Favourorg/Stellar-forge/issues/487)) ([b50b182](https://github.com/Favourorg/Stellar-forge/commit/b50b18207842a21052d69f1a85c67f893e36231a)) +- **contract:** add optional max supply cap to tokens ([#483](https://github.com/Favourorg/Stellar-forge/issues/483)) ([dc00eb6](https://github.com/Favourorg/Stellar-forge/commit/dc00eb6f44e00cdc437c4824c474cb227837dfef)) +- **contract:** add treasury fee split mechanism ([#485](https://github.com/Favourorg/Stellar-forge/issues/485)) ([d933acf](https://github.com/Favourorg/Stellar-forge/commit/d933acfc8876eb3f0db155a0ec7149d04bc2b323)) +- **contract:** emit events for all state-changing functions ([#482](https://github.com/Favourorg/Stellar-forge/issues/482)) ([0a375a8](https://github.com/Favourorg/Stellar-forge/commit/0a375a8a115d2c580d2c1e801e6936102eba4d19)) +- **contracts:** add schema versioning and implement migrate ([7293485](https://github.com/Favourorg/Stellar-forge/commit/7293485078366ff93f43ebb358360ad335dbde12)) +- **contracts:** add schema versioning and implement migrate ([a9fbd2e](https://github.com/Favourorg/Stellar-forge/commit/a9fbd2e525ce9f459d28cfdbc126c3a50ab68919)) +- create WalletConnectButton component ([766c6b9](https://github.com/Favourorg/Stellar-forge/commit/766c6b92eb995d711458cf20585591120ced5d91)) +- enable TypeScript strict mode ([#531](https://github.com/Favourorg/Stellar-forge/issues/531)) ([bb3ad84](https://github.com/Favourorg/Stellar-forge/commit/bb3ad84b61317ddca30bc365f9eb93d4bfc76b28)) +- enforce u128 for initial_supply and add InvalidTokenParams validation [#517](https://github.com/Favourorg/Stellar-forge/issues/517) ([67582a3](https://github.com/Favourorg/Stellar-forge/commit/67582a37491bb016ab44a09f6539321b776a29d0)) +- enhance security, add contract upgrade support, and integrate E2E tests into CI ([5695ca0](https://github.com/Favourorg/Stellar-forge/commit/5695ca0f03c7e7473d50b32cc8be6ca7c41ea560)) +- enhance token factory with DataKey enum and update storage access ([e0c24c0](https://github.com/Favourorg/Stellar-forge/commit/e0c24c04b0f0a9c6b9ea74afd0778915d2256a6f)) +- **explorer:** add Stellar Expert deep links for accounts, transactions, and contracts ([6d509a4](https://github.com/Favourorg/Stellar-forge/commit/6d509a4719802c15ba7a25454bd1cb63e51f4fdc)) +- extract contract error mapping to contractErrors.ts ([0420e56](https://github.com/Favourorg/Stellar-forge/commit/0420e56d1fa61c2f6923fd51f34e199f9d0aa058)) +- **factory:** add offset/limit pagination to get_tokens_by_creator ([#729](https://github.com/Favourorg/Stellar-forge/issues/729)) ([3f88aae](https://github.com/Favourorg/Stellar-forge/commit/3f88aaeb44917ccbcc07bfa5bb6c8fa8c69f1bec)) +- **frontend:** add ipfs gateway URL resolver and stabilize frontend checks ([005ff3f](https://github.com/Favourorg/Stellar-forge/commit/005ff3f36d8e792c1aae283a908f8e34f4540440)) +- **frontend:** block writes on network mismatch in metadata + admin forms ([#906](https://github.com/Favourorg/Stellar-forge/issues/906)) ([f6e88f3](https://github.com/Favourorg/Stellar-forge/commit/f6e88f390e3f87e5abd34ce35989c5907b83bd98)) +- **frontend:** implement i18n support with es and pt translations ([dcbc1b2](https://github.com/Favourorg/Stellar-forge/commit/dcbc1b2838650f7d285d92ffec61a226f0dd28df)) +- **frontend:** wire network-mismatch banner + FAQ page, drop dead duplicate, fix repo URLs ([901021f](https://github.com/Favourorg/Stellar-forge/commit/901021f9ce8eac98d3d50bf5970006818bd835f8)) +- gate wallet and metadata actions behind ToS ([8318679](https://github.com/Favourorg/Stellar-forge/commit/8318679a05a77d2324ef1032e5a8735df50de38b)) +- global error boundary, toast system, and service error cleanup ([19dbf05](https://github.com/Favourorg/Stellar-forge/commit/19dbf055d8666ad6c29cfb08330d54dba1c37da2)) +- global error boundary, toast system, and service error cleanup ([6ca83ad](https://github.com/Favourorg/Stellar-forge/commit/6ca83ad43e48b722d1decf01505c7df900926b39)) +- **hooks:** add LRU eviction to useTokens module-level cache ([#967](https://github.com/Favourorg/Stellar-forge/issues/967)) ([25ca799](https://github.com/Favourorg/Stellar-forge/commit/25ca799e4b03c97a3d52752f7ccbdda0e0820816)) +- **hooks:** add useTransaction hook for transaction lifecycle ([#489](https://github.com/Favourorg/Stellar-forge/issues/489)) ([18debc3](https://github.com/Favourorg/Stellar-forge/commit/18debc33c6bc0dd55ebb830be061c32663b9b2bd)) +- implement BigInt-safe formatting utilities ([fc30b37](https://github.com/Favourorg/Stellar-forge/commit/fc30b3739e3829c47c164b5fc3ed766a720160e7)) +- implement burn_enabled per-token flag ([7d265e8](https://github.com/Favourorg/Stellar-forge/commit/7d265e844a3490af982d1665e0d6d17287a21ad1)) +- Implement Freighter Wallet Integration ([b91a66e](https://github.com/Favourorg/Stellar-forge/commit/b91a66ea7d8ca5e98b04da98c036bde9103896a8)) +- implement Freighter wallet integration ([#666](https://github.com/Favourorg/Stellar-forge/issues/666)) ([8416cfd](https://github.com/Favourorg/Stellar-forge/commit/8416cfd8dd76863b1142ec6662bd063a5eb5c2c8)) +- implement global error boundary ([#473](https://github.com/Favourorg/Stellar-forge/issues/473)) ([d83fe50](https://github.com/Favourorg/Stellar-forge/commit/d83fe50a891c8e6b0ddf9657f533068d85ae8d9d)) +- implement Horizon API retry logic with exponential backoff and Retry-After handling [#499](https://github.com/Favourorg/Stellar-forge/issues/499) ([cfd31b5](https://github.com/Favourorg/Stellar-forge/commit/cfd31b5b7d3cb95c5a4ac367ed93ec95da884a5f)) +- implement mobile-responsive design for all components ([cfdf285](https://github.com/Favourorg/Stellar-forge/commit/cfdf285acfd73648d3ddb9189c9603994e422016)) +- implement pagination for token dashboard ([#29](https://github.com/Favourorg/Stellar-forge/issues/29)) ([9aa41b1](https://github.com/Favourorg/Stellar-forge/commit/9aa41b1489fc9a4b07d3be68c6f2521197a402f0)) +- implement Pinata IPFS upload service with tests ([6b33365](https://github.com/Favourorg/Stellar-forge/commit/6b33365592b88e4835ff4b0728bfd33fe5c65504)) +- implement Pinata IPFS upload with progress tracking and error handling ([53b3684](https://github.com/Favourorg/Stellar-forge/commit/53b368444cefd75a4ab1ae0ad0856244b78d0d59)) +- implement responsive mobile layout (issue [#616](https://github.com/Favourorg/Stellar-forge/issues/616)) ([49ddf41](https://github.com/Favourorg/Stellar-forge/commit/49ddf41412597f035283a56ce005728838a7bf8e)) +- implement reusable CopyButton component with Clipboard API integration ([2f8b716](https://github.com/Favourorg/Stellar-forge/commit/2f8b71673d4bcfed75cea83aba41ba75c7d39d59)) +- implement Soroban contract invocation logic in StellarService ([3a4af37](https://github.com/Favourorg/Stellar-forge/commit/3a4af37b668bc7dd633dca8f80ab34230a160da8)) +- implement Soroban RPC interactions in stellar.ts ([42c9d18](https://github.com/Favourorg/Stellar-forge/commit/42c9d18240eccc884dcee88d0e56e1897fe2a7de)) +- implement StellarService with full Soroban RPC integration ([3f0a520](https://github.com/Favourorg/Stellar-forge/commit/3f0a52060e1264e34239d59ede6542c9a2791bf6)) +- implement token burn UI and service ([a199523](https://github.com/Favourorg/Stellar-forge/commit/a19952319a4e6efc77ccf128bd72ac0fe6fdc2e3)) +- implement Token Dashboard page ([#673](https://github.com/Favourorg/Stellar-forge/issues/673)) ([c3b204c](https://github.com/Favourorg/Stellar-forge/commit/c3b204c15fcca7827fd91c69f97cc0708395e3a8)) +- implement token detail page ([a79ef19](https://github.com/Favourorg/Stellar-forge/commit/a79ef19b62d87c742306511e4c6d4194f47f4301)) +- implement TokenDashboard page with TokenCard component and index-based pagination ([4af373b](https://github.com/Favourorg/Stellar-forge/commit/4af373b0d6ae3928d8c9f09f6fec2e181c1fd857)) +- implement TokenDetail page ([#470](https://github.com/Favourorg/Stellar-forge/issues/470)) ([71ca751](https://github.com/Favourorg/Stellar-forge/commit/71ca75186290f61636b5217b0e4817d8d70d5860)) +- implement TokenDetail page with IPFS metadata, mint/burn/set-metadata inline forms, and 404 state ([9c7f0eb](https://github.com/Favourorg/Stellar-forge/commit/9c7f0eb21f1218f5ad84e0026eb007b6760fcf49)) +- implement transaction status tracking ([#681](https://github.com/Favourorg/Stellar-forge/issues/681)) ([3c0a793](https://github.com/Favourorg/Stellar-forge/commit/3c0a79320128a7e0ebe31f2c6c2091dedbabc790)) +- implement update_treasury in token-factory ([0c381d3](https://github.com/Favourorg/Stellar-forge/commit/0c381d364fc58b048d6ac3b5a3c8e2fdb014a4d4)) +- implement useLocalStorage for dark mode context and add tests for useDarkMode hook ([f04664c](https://github.com/Favourorg/Stellar-forge/commit/f04664cf78bf2f23ca284ae6d8f7807432928a30)) +- implement useLocalStorage hook and integrate for Dark Mode, Network, and Language [#518](https://github.com/Favourorg/Stellar-forge/issues/518) ([9a25f84](https://github.com/Favourorg/Stellar-forge/commit/9a25f843fb0e4aa8c1cd12c84a1e045243386228)) +- implement useTokens hook with parallel fetching and cache ([d9cc12d](https://github.com/Favourorg/Stellar-forge/commit/d9cc12d47d2b1f03c90a062a7a4c43e5a8b9d16f)), closes [#16](https://github.com/Favourorg/Stellar-forge/issues/16) +- implement wallet auto-reconnect and Freighter event listeners ([4cba9dc](https://github.com/Favourorg/Stellar-forge/commit/4cba9dc763125c9a8fa920a14aa94eb91f241835)) +- integrate Sentry error tracking for failed contract calls ([e0cb9f9](https://github.com/Favourorg/Stellar-forge/commit/e0cb9f995c7d04606937ca8c1df0cd923e71c96d)), closes [#757](https://github.com/Favourorg/Stellar-forge/issues/757) +- **ipfs:** implement IPFS metadata upload via Pinata ([#669](https://github.com/Favourorg/Stellar-forge/issues/669)) ([949bcc3](https://github.com/Favourorg/Stellar-forge/commit/949bcc3dc44b247c9fc084edd83cac814a510dd2)) +- Mint Tokens UI with RHF validation and token dropdown ([#674](https://github.com/Favourorg/Stellar-forge/issues/674)) ([223235d](https://github.com/Favourorg/Stellar-forge/commit/223235d8b6d6995d04610e0103b44853d267c4f4)) +- mobile responsive design ([90814c2](https://github.com/Favourorg/Stellar-forge/commit/90814c291d43fc2cc5cb1082eaedb49d70b8f228)) +- **monitoring:** add monitoring docs and sentry dependency ([e043a5c](https://github.com/Favourorg/Stellar-forge/commit/e043a5c4778490cdc5f61a5a6a8bec84f04a97e0)) +- **monitoring:** add Sentry, uptime monitoring, and health endpoint ([cee6369](https://github.com/Favourorg/Stellar-forge/commit/cee6369984c5aa792f631cb2d99f5387f523a675)) +- move wallet state to global React Context ([6c24340](https://github.com/Favourorg/Stellar-forge/commit/6c243409493ecaf75dcaf7020b07e51fa764489e)) +- network switcher with mainnet warning and localStorage persistence ([5fa8531](https://github.com/Favourorg/Stellar-forge/commit/5fa8531fe7735ea781dfdcc3d0393e43b2392138)) +- pause/unpause factory already implemented; add burn-while-paused test ([#480](https://github.com/Favourorg/Stellar-forge/issues/480)) ([4dd54ca](https://github.com/Favourorg/Stellar-forge/commit/4dd54cae186d0f659b02c09174ef52b8c45d40bd)) +- provide services via StellarContext, re-init on network change ([4f924de](https://github.com/Favourorg/Stellar-forge/commit/4f924de5f21060928b716c73263e9dde08eb6232)) +- **security:** add Content Security Policy and security headers ([19f0f1f](https://github.com/Favourorg/Stellar-forge/commit/19f0f1f1a414ff3aaa40c7d880892ae53d0fb494)) +- **security:** add dependency audit and Dependabot configuration ([9f404c1](https://github.com/Favourorg/Stellar-forge/commit/9f404c125b296e2693acefd67f2e6c0c1476f987)), closes [hi#severity](https://github.com/hi/issues/severity) [#502](https://github.com/Favourorg/Stellar-forge/issues/502) +- **security:** add strict CSP, X-Frame-Options, and X-Content-Type-Options headers ([a625191](https://github.com/Favourorg/Stellar-forge/commit/a625191242ad136c2f085d1524916a0781bbc0ea)) +- show XLM/USD equivalent in FeeDisplay component ([fd3c20d](https://github.com/Favourorg/Stellar-forge/commit/fd3c20d6172b5f12542e4822efc0e193e64b9f37)), closes [#733](https://github.com/Favourorg/Stellar-forge/issues/733) +- toast notification system already implemented ([#474](https://github.com/Favourorg/Stellar-forge/issues/474)) ([73b04c9](https://github.com/Favourorg/Stellar-forge/commit/73b04c93422a042df4c9343a024b0d799f062b65)) +- **token-factory:** validate create_token params and use InvalidParameters error ([4e7abc4](https://github.com/Favourorg/Stellar-forge/commit/4e7abc445ef9bb859033a1154087f4e06c60d426)) +- **ui:** add DropZone drag-and-drop component and replace file input in MetadataUploadForm ([fee9791](https://github.com/Favourorg/Stellar-forge/commit/fee979106b6aa2f6cabdae7a8d89e34187fb4516)) +- **ui:** add network-aware Stellar Expert explorer links ([20dced8](https://github.com/Favourorg/Stellar-forge/commit/20dced85535f61c3700295b38486148e21fcee85)), closes [#621](https://github.com/Favourorg/Stellar-forge/issues/621) +- **ui:** confirmation modal before every state-changing transaction ([#490](https://github.com/Favourorg/Stellar-forge/issues/490)) ([88291e3](https://github.com/Favourorg/Stellar-forge/commit/88291e3a54fb6581068f0aa474301effc8d5839f)) +- **ui:** implement MetadataForm with IPFS upload + Stellar linking ([#676](https://github.com/Favourorg/Stellar-forge/issues/676)) ([20f5327](https://github.com/Favourorg/Stellar-forge/commit/20f53270a24aafadba31984dde41b3b1f4605ad7)) +- upgrade mechanism, ADRs, QR code sharing, onboarding tutorial ([7b59535](https://github.com/Favourorg/Stellar-forge/commit/7b5953553e50e0d011aefd8d581d346cd03eef0d)), closes [#1](https://github.com/Favourorg/Stellar-forge/issues/1) [#2](https://github.com/Favourorg/Stellar-forge/issues/2) [#3](https://github.com/Favourorg/Stellar-forge/issues/3) [#4](https://github.com/Favourorg/Stellar-forge/issues/4) +- **ux:** insufficient balance warning before transaction submission ([#496](https://github.com/Favourorg/Stellar-forge/issues/496)) ([0777d93](https://github.com/Favourorg/Stellar-forge/commit/0777d937bf16c0428cc0c9b8981bcf6322cfba66)) +- wire setMetadata to StellarService in TokenDetail ([04de946](https://github.com/Favourorg/Stellar-forge/commit/04de946b9f1be0b11b385f12dd0138798cb79437)) +- wire up mint and burn token UI to contract ([ca6b7b4](https://github.com/Favourorg/Stellar-forge/commit/ca6b7b41537ff00ac62d56316089355f62a6b188)), closes [#541](https://github.com/Favourorg/Stellar-forge/issues/541) ### Performance Improvements -* apply useMemo, useCallback, and React.memo for render optimizations ([8afb78a](https://github.com/Favourorg/Stellar-forge/commit/8afb78ab2911e0681f21866959e39a6fbf41e427)) -* fetch creator token pages concurrently with capped concurrency ([#969](https://github.com/Favourorg/Stellar-forge/issues/969)) ([bfdc828](https://github.com/Favourorg/Stellar-forge/commit/bfdc8285861c5382f87933f48f45c85dfdc50c5d)), closes [#16](https://github.com/Favourorg/Stellar-forge/issues/16) -* **frontend:** implement route-level code splitting and lazy load stellar-sdk ([a9ed488](https://github.com/Favourorg/Stellar-forge/commit/a9ed488c4633a910765ae678de6f5cc63589a4e2)) +- apply useMemo, useCallback, and React.memo for render optimizations ([8afb78a](https://github.com/Favourorg/Stellar-forge/commit/8afb78ab2911e0681f21866959e39a6fbf41e427)) +- fetch creator token pages concurrently with capped concurrency ([#969](https://github.com/Favourorg/Stellar-forge/issues/969)) ([bfdc828](https://github.com/Favourorg/Stellar-forge/commit/bfdc8285861c5382f87933f48f45c85dfdc50c5d)), closes [#16](https://github.com/Favourorg/Stellar-forge/issues/16) +- **frontend:** implement route-level code splitting and lazy load stellar-sdk ([a9ed488](https://github.com/Favourorg/Stellar-forge/commit/a9ed488c4633a910765ae678de6f5cc63589a4e2)) diff --git a/ISSUES.md b/ISSUES.md index 83a27124..724a94fc 100644 --- a/ISSUES.md +++ b/ISSUES.md @@ -2,38 +2,38 @@ This file tracks issues identified during the August 2026 codebase audit (30 issues total). -| # | Area | Severity | Title | Status | -|---|------|----------|-------|--------| -| 1 | — | — | *(pending)* | Open | -| 2 | — | — | *(pending)* | Open | -| 3 | — | — | *(pending)* | Open | -| 4 | — | — | *(pending)* | Open | -| **5** | **API (`api/auth/challenge.ts`)** | **High** | **`verifyStellarSignature` used wrong payload + broken `tweetnacl` import — every login silently rejected** | **✅ Resolved** | -| 6 | — | — | *(pending)* | Open | -| 7 | — | — | *(pending)* | Open | -| 8 | — | — | *(pending)* | Open | -| 9 | — | — | *(pending)* | Open | -| 10 | — | — | *(pending)* | Open | -| 11 | — | — | *(pending)* | Open | -| 12 | — | — | *(pending)* | Open | -| 13 | — | — | *(pending)* | Open | -| 14 | — | — | *(pending)* | Open | -| 15 | — | — | *(pending)* | Open | -| 16 | — | — | *(pending)* | Open | -| 17 | — | — | *(pending)* | Open | -| 18 | — | — | *(pending)* | Open | -| 19 | — | — | *(pending)* | Open | -| 20 | — | — | *(pending)* | Open | -| 21 | — | — | *(pending)* | Open | -| 22 | — | — | *(pending)* | Open | -| 23 | — | — | *(pending)* | Open | -| 24 | — | — | *(pending)* | Open | -| 25 | — | — | *(pending)* | Open | -| **26** | **API (`api/_lib/rateLimit.ts`)** | **Medium-Low** | **`clientIp()` had inverted/incorrect X-Forwarded-For parsing** | **✅ Resolved** | -| 27 | — | — | *(pending)* | Open | -| 28 | — | — | *(pending)* | Open | -| 29 | — | — | *(pending)* | Open | -| 30 | — | — | *(pending)* | Open | +| # | Area | Severity | Title | Status | +| ------ | --------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------- | --------------- | +| 1 | — | — | _(pending)_ | Open | +| 2 | — | — | _(pending)_ | Open | +| 3 | — | — | _(pending)_ | Open | +| 4 | — | — | _(pending)_ | Open | +| **5** | **API (`api/auth/challenge.ts`)** | **High** | **`verifyStellarSignature` used wrong payload + broken `tweetnacl` import — every login silently rejected** | **✅ Resolved** | +| 6 | — | — | _(pending)_ | Open | +| 7 | — | — | _(pending)_ | Open | +| 8 | — | — | _(pending)_ | Open | +| 9 | — | — | _(pending)_ | Open | +| 10 | — | — | _(pending)_ | Open | +| 11 | — | — | _(pending)_ | Open | +| 12 | — | — | _(pending)_ | Open | +| 13 | — | — | _(pending)_ | Open | +| 14 | — | — | _(pending)_ | Open | +| 15 | — | — | _(pending)_ | Open | +| 16 | — | — | _(pending)_ | Open | +| 17 | — | — | _(pending)_ | Open | +| 18 | — | — | _(pending)_ | Open | +| 19 | — | — | _(pending)_ | Open | +| 20 | — | — | _(pending)_ | Open | +| 21 | — | — | _(pending)_ | Open | +| 22 | — | — | _(pending)_ | Open | +| 23 | — | — | _(pending)_ | Open | +| 24 | — | — | _(pending)_ | Open | +| 25 | — | — | _(pending)_ | Open | +| **26** | **API (`api/_lib/rateLimit.ts`)** | **Medium-Low** | **`clientIp()` had inverted/incorrect X-Forwarded-For parsing** | **✅ Resolved** | +| 27 | — | — | _(pending)_ | Open | +| 28 | — | — | _(pending)_ | Open | +| 29 | — | — | _(pending)_ | Open | +| 30 | — | — | _(pending)_ | Open | --- @@ -55,8 +55,8 @@ This was wrong in two compounding ways: 1. **Standard XFF semantics**: The client IP is the **leftmost** entry; subsequent entries are proxies appended in order. Taking the rightmost yields a proxy IP, not the client. 2. **Vercel's actual behaviour**: [Vercel's documentation](https://vercel.com/docs/headers/request-headers#x-forwarded-for) - states that `x-forwarded-for` contains *"The public IP address of the client that made - the request"* and that Vercel **overwrites** the header (does not forward external IPs) + states that `x-forwarded-for` contains _"The public IP address of the client that made + the request"_ and that Vercel **overwrites** the header (does not forward external IPs) to prevent IP spoofing. On Vercel, the header is always a single IP — the real client IP — making multi-hop parsing entirely moot. @@ -107,12 +107,13 @@ that caused **every POST `/api/auth/challenge` login attempt to silently return 3. **Broken `tweetnacl` import**: `const { sign } = await import('tweetnacl')` attempts named-export destructuring from a CJS module; `sign` is `undefined` at runtime. Every `sign.detached.verify(...)` call threw `TypeError: Cannot read properties - of undefined (reading 'detached')`, which the catch block turned into `return false`. +of undefined (reading 'detached')`, which the catch block turned into `return false`. `tweetnacl` was also only a transitive dependency, not declared in `package.json`. ### Resolution `verifyStellarSignature` was rewritten to: + - Construct the SEP-53 payload: `SHA256("Stellar Signed Message:\n" + challenge)` using Node's built-in `crypto` module (no new dependencies). - Decode the base64 signature to raw bytes. @@ -123,6 +124,7 @@ that caused **every POST `/api/auth/challenge` login attempt to silently return inline comments to accurately describe the SEP-53 wire format. Four cryptographic unit tests were added to `challenge.test.ts` covering: + - Valid signature → 200 + JWT - Tampered signature → 401 - Signature for wrong challenge → 401 diff --git a/README.md b/README.md index 2b382e85..23c47dd1 100644 --- a/README.md +++ b/README.md @@ -292,11 +292,11 @@ The authoritative, field-by-field reference — including parameter tables, ever ### Errors -All fallible entrypoints return `Result`. See the full table (25 variants, e.g. `InsufficientFee`, `Unauthorized`, `ContractPaused`, `MaxSupplyExceeded`, `InvalidFeeSplit`, `NoPendingProposal`, `ProposalExpired`) in [`docs/contract-abi.md`](./docs/contract-abi.md#errors). +All fallible entrypoints return `Result`. See the full table (27 variants, e.g. `InsufficientFee`, `Unauthorized`, `ContractPaused`, `MaxSupplyExceeded`, `InvalidFeeSplit`, `NoPendingProposal`, `ProposalExpired`) in [`docs/contract-abi.md`](./docs/contract-abi.md#errors). ### Events -The contract publishes Soroban events on `(factory, action)` topics — `init`, `created`, `meta`, `mint`, `burn`, `fees`, `pause`, `unpause`, `adm_upd` — parsed by the frontend in `frontend/src/services/stellar-impl.ts` and rendered in the Transaction History view. See [`docs/contract-abi.md`](./docs/contract-abi.md#events) for the exact payload of each. +The contract publishes Soroban events on `(factory, action)` topics — `init`, `created`, `meta`, `mint`, `burn`, `fees`, `pause`, `unpause`, `adm_prop`, `adm_acc`, `adm_can` — parsed by the frontend in `frontend/src/services/stellar-impl.ts` and rendered in the Transaction History view. See [`docs/contract-abi.md`](./docs/contract-abi.md#events) for the exact payload of each. ## Usage @@ -980,7 +980,7 @@ The factory contract supports in-place WASM upgrades without redeploying or migr | 1 | Initial versioned schema — added `schema_version` field to `FactoryState` | | 2 | Max-supply accounting fix (issue #1006) — `deploy_one` now seeds the per-token supply counter with `initial_supply`; version bump only, no `FactoryState` field changes. Pre-fix capped tokens must be back-filled individually via `backfill_capped_supply` (see [docs/contract-abi.md](./docs/contract-abi.md#supply-cap-accounting)) | | 3 | Persistent-storage migration (issue #1007) — per-token bookkeeping (`TokenInfo`, `TokenIndex`, `Metadata`, `owner`, `supply`, `CreatorTokens`) moves out of the shared `instance` ledger entry into `persistent` storage, keeping `instance` storage O(1) in `token_count`. `TokenInfo` migrates in bounded, resumable chunks per `migrate` call; everything else migrates lazily on next access (see [docs/contract-abi.md](./docs/contract-abi.md#storage-architecture)) | -| 4 | Two-step admin rotation — added `pending_admin: Option
` and `pending_admin_expiry: Option` to `FactoryState`; new `propose_admin`, `accept_admin`, `cancel_admin_proposal` entrypoints; `transfer_admin` and `update_admin` now delegate to `propose_admin` (no single-step rotation path remains). New error codes 24 (`NoPendingProposal`) and 25 (`ProposalExpired`). New events `adm_prop`, `adm_acc`, `adm_can`. | +| 4 | Two-step admin rotation — added `pending_admin: Option
` and `pending_admin_expiry: Option` to `FactoryState`; new `propose_admin`, `accept_admin`, `cancel_admin_proposal` entrypoints; `transfer_admin` and `update_admin` now delegate to `propose_admin` (no single-step rotation path remains). New error codes 26 (`NoPendingProposal`) and 27 (`ProposalExpired`). New events `adm_prop`, `adm_acc`, `adm_can`. | ### Adding a new migration (version N → N+1) diff --git a/SECURITY.md b/SECURITY.md index 7e4c89fc..c547e1e2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -60,6 +60,10 @@ The factory contract's `admin` address can upgrade the contract, change fees, re The `upgrade` function currently emits no Soroban event. Detection of a malicious WASM replacement currently requires active polling of the on-chain WASM hash. The monitoring script is documented in the [Incident Response Runbook](./docs/incident-response.md#22-wasm-hash-polling-required-until-issue-9-is-resolved). +### IPFS unpin requires CID ownership (issue #1155) + +`POST /api/ipfs/unpin` requires more than a valid JWT: any wallet can obtain one for free via the challenge/response flow, so JWT possession alone does not prove a right to delete someone else's pinned content. The endpoint additionally checks the requesting wallet address against an ownership record captured at upload time (`api/_lib/pinOwnership.ts`, populated by `upload-json.ts` / `upload-file.ts`). A CID with no ownership record on file is **denied by default** — it is never treated as unpinnable-by-anyone. See `api/ipfs/unpin.ts` and its regression tests in `api/ipfs/unpin.test.ts`. + ### Content Security Policy A strict CSP is enforced both as a `` tag and via HTTP response headers on the hosted deployment. See the [README](./README.md#content-security-policy-csp) for configuration details. diff --git a/api/_lib/pinOwnership.ts b/api/_lib/pinOwnership.ts new file mode 100644 index 00000000..9bec1662 --- /dev/null +++ b/api/_lib/pinOwnership.ts @@ -0,0 +1,122 @@ +/** + * Tracks which wallet address pinned a given IPFS CID, so the unpin endpoint + * can verify ownership before deleting content from Pinata on someone's + * behalf. Recorded at upload time by upload-json.ts / upload-file.ts. + * + * Uses Vercel KV for durability across serverless instances, matching the + * pattern in rateLimit.ts. Falls back to per-instance memory when KV isn't + * configured — note that this fallback fails *closed*: a CID pinned by one + * instance won't be found by a different instance's in-memory map, so + * getPinOwner() returns null and the caller denies the unpin. Configure + * Vercel KV in production so legitimate owners aren't denied. + */ + +interface PinOwnerRecord { + ownerAddress: string; + pinnedAt: number; +} + +const memoryRegistry = new Map(); + +function pinKey(cid: string): string { + return `pinowner:${cid}`; +} + +/** Records the wallet address that pinned `cid`. Called after a successful Pinata pin. */ +export async function recordPinOwner( + cid: string, + ownerAddress: string, +): Promise { + const kvUrl = process.env.VERCEL_KV_REST_API_URL; + const kvToken = process.env.VERCEL_KV_REST_API_TOKEN; + const record: PinOwnerRecord = { ownerAddress, pinnedAt: Date.now() }; + + if (kvUrl && kvToken) { + try { + await kvSet(kvUrl, kvToken, pinKey(cid), JSON.stringify(record)); + return; + } catch (err) { + console.error( + "Failed to record pin owner in KV, falling back to memory:", + err, + ); + } + } + + memoryRegistry.set(cid, record); +} + +/** + * Returns the wallet address that pinned `cid`, or null if the CID is not + * indexed. Callers MUST treat null as "ownership cannot be verified" and + * deny the request — never allow-by-default for an unknown CID. + */ +export async function getPinOwner(cid: string): Promise { + const kvUrl = process.env.VERCEL_KV_REST_API_URL; + const kvToken = process.env.VERCEL_KV_REST_API_TOKEN; + + if (kvUrl && kvToken) { + try { + const data = await kvGet(kvUrl, kvToken, pinKey(cid)); + if (!data) return null; + const record = JSON.parse(data) as PinOwnerRecord; + return record.ownerAddress; + } catch (err) { + console.error("Failed to read pin owner from KV:", err); + return null; + } + } + + return memoryRegistry.get(cid)?.ownerAddress ?? null; +} + +/** Removes ownership tracking for `cid` after it has been successfully unpinned. */ +export async function clearPinOwner(cid: string): Promise { + const kvUrl = process.env.VERCEL_KV_REST_API_URL; + const kvToken = process.env.VERCEL_KV_REST_API_TOKEN; + + if (kvUrl && kvToken) { + try { + await kvDel(kvUrl, kvToken, pinKey(cid)); + return; + } catch (err) { + console.error("Failed to clear pin owner from KV:", err); + } + } + + memoryRegistry.delete(cid); +} + +// Vercel KV REST API helpers (mirrors rateLimit.ts) +async function kvGet( + url: string, + token: string, + key: string, +): Promise { + const response = await fetch(`${url}/get/${encodeURIComponent(key)}`, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (!response.ok) return null; + const data = (await response.json()) as { result: string | null }; + return data.result; +} + +async function kvSet( + url: string, + token: string, + key: string, + value: string, +): Promise { + await fetch(`${url}/set/${encodeURIComponent(key)}`, { + method: "POST", + headers: { Authorization: `Bearer ${token}` }, + body: JSON.stringify({ value }), + }); +} + +async function kvDel(url: string, token: string, key: string): Promise { + await fetch(`${url}/del/${encodeURIComponent(key)}`, { + method: "POST", + headers: { Authorization: `Bearer ${token}` }, + }); +} diff --git a/api/_lib/schemaValidation.ts b/api/_lib/schemaValidation.ts index 911b610f..40a32e26 100644 --- a/api/_lib/schemaValidation.ts +++ b/api/_lib/schemaValidation.ts @@ -4,15 +4,24 @@ */ export interface TokenMetadata { - name: string - description: string - image: string // Must be ipfs://CID format + name: string; + description: string; + image: string; // Must be ipfs://CID format } -const MAX_METADATA_JSON_SIZE = 8 * 1024 // 8 KiB strict limit -const MAX_NAME_LENGTH = 128 -const MAX_DESCRIPTION_LENGTH = 2000 -const IPFS_URI_PATTERN = /^ipfs:\/\/[a-zA-Z0-9]+$/ +const MAX_METADATA_JSON_SIZE = 8 * 1024; // 8 KiB strict limit +const MAX_NAME_LENGTH = 128; +const MAX_DESCRIPTION_LENGTH = 2000; +const IPFS_URI_PATTERN = /^ipfs:\/\/[a-zA-Z0-9]+$/; + +// CIDv0: Qm + 44 base58 chars (total 46); CIDv1: b + base32 (lowercase) +const CID_V0_PATTERN = /^Qm[1-9A-HJ-NP-Za-km-z]{44}$/; +const CID_V1_PATTERN = /^b[a-z2-7]{58,}$/; + +/** Validates a bare IPFS CID (no `ipfs://` prefix), CIDv0 or CIDv1. */ +export function isValidCid(cid: string): boolean { + return CID_V0_PATTERN.test(cid) || CID_V1_PATTERN.test(cid); +} /** * Validate a TokenMetadata object and its JSON serialization. @@ -29,49 +38,53 @@ export function validateTokenMetadata( return { valid: false, error: `Metadata exceeds maximum size of ${MAX_METADATA_JSON_SIZE} bytes.`, - } + }; } // Type check - if (typeof metadata !== 'object' || metadata === null) { - return { valid: false, error: 'Metadata must be a JSON object.' } + if (typeof metadata !== "object" || metadata === null) { + return { valid: false, error: "Metadata must be a JSON object." }; } - const obj = metadata as Record + const obj = metadata as Record; // Required fields - if (typeof obj.name !== 'string' || obj.name.length === 0 || obj.name.length > MAX_NAME_LENGTH) { + if ( + typeof obj.name !== "string" || + obj.name.length === 0 || + obj.name.length > MAX_NAME_LENGTH + ) { return { valid: false, error: `name must be a non-empty string, max ${MAX_NAME_LENGTH} characters.`, - } + }; } if ( - typeof obj.description !== 'string' || + typeof obj.description !== "string" || obj.description.length === 0 || obj.description.length > MAX_DESCRIPTION_LENGTH ) { return { valid: false, error: `description must be a non-empty string, max ${MAX_DESCRIPTION_LENGTH} characters.`, - } + }; } - if (typeof obj.image !== 'string' || !IPFS_URI_PATTERN.test(obj.image)) { + if (typeof obj.image !== "string" || !IPFS_URI_PATTERN.test(obj.image)) { return { valid: false, - error: 'image must be in ipfs://CID format (e.g., ipfs://QmXxxx).', - } + error: "image must be in ipfs://CID format (e.g., ipfs://QmXxxx).", + }; } // No extra fields allowed - const allowedKeys = new Set(['name', 'description', 'image']) + const allowedKeys = new Set(["name", "description", "image"]); for (const key of Object.keys(obj)) { if (!allowedKeys.has(key)) { - return { valid: false, error: `Unexpected field: ${key}.` } + return { valid: false, error: `Unexpected field: ${key}.` }; } } - return { valid: true } + return { valid: true }; } diff --git a/api/auth/challenge.test.ts b/api/auth/challenge.test.ts index cb11301c..b01b5974 100644 --- a/api/auth/challenge.test.ts +++ b/api/auth/challenge.test.ts @@ -200,13 +200,15 @@ describe('rate limiting', () => { it('calls isRateLimited with the address for POST', async () => { await putChallenge(ADDRESS, 'deadbeef') - await handler(post({ address: ADDRESS, signature: 'c2lnbmF0dXJl' }).req, post({ address: ADDRESS, signature: 'c2lnbmF0dXJl' }).res) + await handler( + post({ address: ADDRESS, signature: 'c2lnbmF0dXJl' }).req, + post({ address: ADDRESS, signature: 'c2lnbmF0dXJl' }).res, + ) expect(mockIsRateLimited).toHaveBeenCalledWith(ADDRESS) }) }) - /** * Cryptographic round-trip tests for verifyStellarSignature. * @@ -310,4 +312,3 @@ describe('verifyStellarSignature — cryptographic paths', () => { expect(status).toHaveBeenCalledWith(401) }) }) - diff --git a/api/health/indexer.test.ts b/api/health/indexer.test.ts index 9f3aaaa2..3241c061 100644 --- a/api/health/indexer.test.ts +++ b/api/health/indexer.test.ts @@ -23,10 +23,7 @@ function fakeReqRes(method = 'GET') { type MockStore = Pick -function mockStore( - overrides: Partial = {}, - tokenCount = 42, -): MockStore { +function mockStore(overrides: Partial = {}, tokenCount = 42): MockStore { const state: IndexerState = { lastCursor: 'abc', lastLedger: 12345, @@ -100,7 +97,8 @@ describe('GET /api/health/indexer', () => { }) it('never contains raw driver error strings in the response', async () => { - const rawError = 'connect() to PostgreSQL at postgresql://admin:hunter2@internal-db-1.example.com:5432/stellarforge failed: could not connect to server: Connection refused' + const rawError = + 'connect() to PostgreSQL at postgresql://admin:hunter2@internal-db-1.example.com:5432/stellarforge failed: could not connect to server: Connection refused' store = mockStore({ lastError: rawError }) const { req, res, json } = fakeReqRes() @@ -159,4 +157,4 @@ describe('GET /api/health/indexer', () => { expect(json).toHaveBeenCalledWith({ error: 'Method not allowed' }) }) }) -}) \ No newline at end of file +}) diff --git a/api/health/indexer.ts b/api/health/indexer.ts index 72c43376..c53e8f6f 100644 --- a/api/health/indexer.ts +++ b/api/health/indexer.ts @@ -43,11 +43,7 @@ function sanitizeIndexerError(raw: string | null): string | null { } // Query-level timeouts - if ( - lower.includes('timeout') || - lower.includes('timed out') || - lower.includes('query timeout') - ) { + if (lower.includes('timeout') || lower.includes('timed out') || lower.includes('query timeout')) { return 'query_timeout' } diff --git a/api/ipfs/unpin.test.ts b/api/ipfs/unpin.test.ts index c433f308..b514742b 100644 --- a/api/ipfs/unpin.test.ts +++ b/api/ipfs/unpin.test.ts @@ -2,15 +2,16 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import type { VercelRequest, VercelResponse } from '@vercel/node' import handler from './unpin' import { issueToken } from '../_lib/jwt' +import { recordPinOwner } from '../_lib/pinOwnership' -function fakeReqRes(body: unknown, token?: string) { - const headers: Record = {} +function fakeReqRes(body: unknown, token: string | undefined, ip = '127.0.0.1') { + const headers: Record = { 'x-forwarded-for': ip } if (token) headers.authorization = `Bearer ${token}` const req = { method: 'POST', headers, - socket: { remoteAddress: '127.0.0.1' }, + socket: { remoteAddress: ip }, body, } as unknown as VercelRequest @@ -21,96 +22,182 @@ function fakeReqRes(body: unknown, token?: string) { return { req, res, status, json } } -let walletCounter = 0 -function freshToken(): string { - walletCounter += 1 - return issueToken(`GUNPINTESTWALLET${walletCounter}`) +/** A syntactically valid CIDv0, unique per test via `seed`. */ +function makeCid(seed: string): string { + return `Qm${seed.padEnd(44, 'a')}` } -const VALID_CID = 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi' +let ipCounter = 0 +/** A fresh loopback-range IP per call, so rate limiting doesn't leak across tests. */ +function freshIp(): string { + ipCounter += 1 + return `203.0.113.${ipCounter}` +} describe('POST /api/ipfs/unpin', () => { beforeEach(() => { + process.env.JWT_SECRET = 'test-jwt-secret' process.env.PINATA_API_KEY = 'test-key' process.env.PINATA_API_SECRET = 'test-secret' - process.env.JWT_SECRET = 'test-jwt-secret' vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue({ ok: true, status: 200, + json: async () => ({}), } as Response), ) }) afterEach(() => { vi.unstubAllGlobals() + delete process.env.JWT_SECRET delete process.env.PINATA_API_KEY delete process.env.PINATA_API_SECRET - delete process.env.JWT_SECRET }) - it('unpins a CID via Pinata using server-side credentials', async () => { - const { req, res, status, json } = fakeReqRes({ cid: VALID_CID }, freshToken()) + it('rejects non-POST methods', async () => { + const { req, res, status } = fakeReqRes({}, undefined, freshIp()) + req.method = 'GET' + + await handler(req, res) + + expect(status).toHaveBeenCalledWith(405) + }) + + it('rejects requests without a valid JWT', async () => { + const cid = makeCid('noauth') + const { req, res, status } = fakeReqRes({ cid }, undefined, freshIp()) + + await handler(req, res) + + expect(status).toHaveBeenCalledWith(401) + expect(fetch).not.toHaveBeenCalled() + }) + + it('rejects a missing cid', async () => { + const token = issueToken('GNOCIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') + const { req, res, status } = fakeReqRes({}, token, freshIp()) + + await handler(req, res) + + expect(status).toHaveBeenCalledWith(400) + expect(fetch).not.toHaveBeenCalled() + }) + + it('rejects a malformed cid before checking ownership', async () => { + const token = issueToken('GREQUESTERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') + const { req, res, status } = fakeReqRes({ cid: 'not-a-real-cid' }, token, freshIp()) + + await handler(req, res) + + expect(status).toHaveBeenCalledWith(400) + expect(fetch).not.toHaveBeenCalled() + }) + + it('denies unpinning a CID with no ownership record on file (deny by default)', async () => { + const cid = makeCid('unknown1') + const token = issueToken('GREQUESTERBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB') + const { req, res, status, json } = fakeReqRes({ cid }, token, freshIp()) + + await handler(req, res) + + expect(status).toHaveBeenCalledWith(403) + expect(json).toHaveBeenCalledWith( + expect.objectContaining({ + error: expect.stringContaining('denied by default'), + }), + ) + expect(fetch).not.toHaveBeenCalled() + }) + + it('denies a wallet that does not own the CID (IDOR check)', async () => { + const cid = makeCid('ownedbyA') + await recordPinOwner(cid, 'GOWNERWALLETAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') + + const attackerToken = issueToken('GATTACKERWALLETBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB') + const { req, res, status, json } = fakeReqRes({ cid }, attackerToken, freshIp()) + + await handler(req, res) + + expect(status).toHaveBeenCalledWith(403) + expect(json).toHaveBeenCalledWith( + expect.objectContaining({ + error: expect.stringContaining('not authorized'), + }), + ) + expect(fetch).not.toHaveBeenCalled() + }) + + it('allows the legitimate owner to unpin their own CID', async () => { + const cid = makeCid('ownedbyB') + const ownerAddress = 'GOWNERWALLETCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' + await recordPinOwner(cid, ownerAddress) + + const ownerToken = issueToken(ownerAddress) + const { req, res, status, json } = fakeReqRes({ cid }, ownerToken, freshIp()) await handler(req, res) expect(status).toHaveBeenCalledWith(200) - expect(json).toHaveBeenCalledWith({ success: true, cid: VALID_CID }) + expect(json).toHaveBeenCalledWith({ cid, unpinned: true }) const [url, options] = vi.mocked(fetch).mock.calls[0] - expect(String(url)).toBe(`https://api.pinata.cloud/pinning/unpin/${VALID_CID}`) + expect(url).toBe(`https://api.pinata.cloud/pinning/unpin/${cid}`) expect((options as RequestInit).method).toBe('DELETE') const headers = (options as RequestInit).headers as Record expect(headers.pinata_api_key).toBe('test-key') - expect(headers.pinata_secret_api_key).toBe('test-secret') }) - it('treats a 404 (CID already gone) as success', async () => { + it('treats a 404 from Pinata (CID already gone) as success for the owner', async () => { + const cid = makeCid('ownedbyD') + const ownerAddress = 'GOWNERWALLETDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD' + await recordPinOwner(cid, ownerAddress) + vi.mocked(fetch).mockResolvedValueOnce({ ok: false, status: 404, } as Response) - const { req, res, status, json } = fakeReqRes({ cid: VALID_CID }, freshToken()) + const ownerToken = issueToken(ownerAddress) + const { req, res, status, json } = fakeReqRes({ cid }, ownerToken, freshIp()) await handler(req, res) expect(status).toHaveBeenCalledWith(200) - expect(json).toHaveBeenCalledWith({ success: true, cid: VALID_CID }) + expect(json).toHaveBeenCalledWith({ cid, unpinned: true }) }) - it('rejects a missing cid', async () => { - const { req, res, status } = fakeReqRes({}, freshToken()) + it('surfaces Pinata rate limiting distinctly from other failures', async () => { + const cid = makeCid('ownedbyE') + const ownerAddress = 'GOWNERWALLETEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE' + await recordPinOwner(cid, ownerAddress) - await handler(req, res) - - expect(status).toHaveBeenCalledWith(400) - }) + vi.mocked(fetch).mockResolvedValueOnce({ + ok: false, + status: 429, + } as Response) - it('rejects a malformed cid', async () => { - const { req, res, status } = fakeReqRes({ cid: '../../etc/passwd' }, freshToken()) + const ownerToken = issueToken(ownerAddress) + const { req, res, status } = fakeReqRes({ cid }, ownerToken, freshIp()) await handler(req, res) - expect(status).toHaveBeenCalledWith(400) + expect(status).toHaveBeenCalledWith(502) }) - it('rejects missing authorization', async () => { - const { req, res, status } = fakeReqRes({ cid: VALID_CID }) - - await handler(req, res) - - expect(status).toHaveBeenCalledWith(401) - }) + it('surfaces other Pinata HTTP failures', async () => { + const cid = makeCid('ownedbyF') + const ownerAddress = 'GOWNERWALLETFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' + await recordPinOwner(cid, ownerAddress) - it('surfaces Pinata HTTP failures', async () => { vi.mocked(fetch).mockResolvedValueOnce({ ok: false, status: 500, } as Response) - const { req, res, status } = fakeReqRes({ cid: VALID_CID }, freshToken()) + const ownerToken = issueToken(ownerAddress) + const { req, res, status } = fakeReqRes({ cid }, ownerToken, freshIp()) await handler(req, res) diff --git a/api/ipfs/unpin.ts b/api/ipfs/unpin.ts index 532554d1..6ab8b317 100644 --- a/api/ipfs/unpin.ts +++ b/api/ipfs/unpin.ts @@ -1,28 +1,21 @@ import type { VercelRequest, VercelResponse } from '@vercel/node' import { isRateLimited } from '../_lib/rateLimit' import { PINATA_API_URL, pinataHeaders } from '../_lib/pinata' +import { isValidCid } from '../_lib/schemaValidation' import { verifyToken } from '../_lib/jwt' +import { getPinOwner, clearPinOwner } from '../_lib/pinOwnership' interface UnpinBody { cid: string } -/** - * Pinata CID pattern: a base58btc multihash (Qm…) for CIDv0 or a base32 - * multihash for CIDv1 (b…). We only ever create CIDv1 pins (cidVersion: 1 in - * the upload proxies), but accept both shapes so a v0 CID from another source - * can still be cleaned up. - */ -const CID_PATTERN = /^(Qm[A-Za-z0-9]{44}|b[a-z2-7]{58})$/ - export default async function handler(req: VercelRequest, res: VercelResponse) { if (req.method !== 'POST') { res.status(405).json({ error: 'Method not allowed' }) return } - // Authenticate: require a valid JWT from the challenge → signature flow, - // mirroring the upload proxies. + // Authenticate: require a valid JWT from the challenge → signature flow const authHeader = req.headers.authorization if (!authHeader || !authHeader.startsWith('Bearer ')) { res.status(401).json({ @@ -50,21 +43,46 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const body = req.body as UnpinBody | undefined - if (!body || typeof body.cid !== 'string' || !CID_PATTERN.test(body.cid)) { + const rawCid = typeof body?.cid === 'string' ? body.cid : null + if (!rawCid || !isValidCid(rawCid)) { + auditUnpin(walletAddress, rawCid ?? '(missing)', 'denied_invalid_cid') res.status(400).json({ error: 'Request body must include a valid { cid: string }.' }) return } + const cid = rawCid + + // Ownership check: a CID may only be unpinned by the wallet that pinned + // it. An unindexed/unknown CID is denied by default — we never assume + // the requester owns content we have no record of. + const ownerAddress = await getPinOwner(cid) + + if (ownerAddress === null) { + auditUnpin(walletAddress, cid, 'denied_unknown_cid') + res.status(403).json({ + error: + 'This CID has no known owner on record. Unpin is denied by default for unindexed content.', + }) + return + } + + if (ownerAddress !== walletAddress) { + auditUnpin(walletAddress, cid, 'denied_not_owner') + res.status(403).json({ error: 'You are not authorized to unpin this content.' }) + return + } let headers: Record try { headers = pinataHeaders() } catch (err) { - res.status(500).json({ error: err instanceof Error ? err.message : 'Server misconfiguration.' }) + res.status(500).json({ + error: err instanceof Error ? err.message : 'Server misconfiguration.', + }) return } try { - const pinataRes = await fetch(`${PINATA_API_URL}/pinning/unpin/${body.cid}`, { + const pinataRes = await fetch(`${PINATA_API_URL}/pinning/unpin/${cid}`, { method: 'DELETE', headers, }) @@ -73,17 +91,35 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { // already gone — both are acceptable outcomes for "make sure it is not // pinned any more". if (pinataRes.ok || pinataRes.status === 404) { - res.status(200).json({ success: true, cid: body.cid }) + await clearPinOwner(cid) + auditUnpin(walletAddress, cid, 'allowed') + res.status(200).json({ cid, unpinned: true }) return } if (pinataRes.status === 429) { + auditUnpin(walletAddress, cid, 'pinata_rate_limited') res.status(502).json({ error: 'Pinata rate limit reached. Please try again later.' }) return } + auditUnpin(walletAddress, cid, 'pinata_error') res.status(502).json({ error: `Pinata unpin failed (HTTP ${pinataRes.status}).` }) } catch { + auditUnpin(walletAddress, cid, 'error') res.status(500).json({ error: 'Unexpected error while unpinning from IPFS.' }) } } + +/** Structured audit log for every unpin attempt, allowed or rejected. */ +function auditUnpin(address: string, cid: string, outcome: string): void { + console.log( + JSON.stringify({ + event: 'ipfs_unpin', + address, + cid, + outcome, + at: new Date().toISOString(), + }), + ) +} diff --git a/api/ipfs/upload-file.ts b/api/ipfs/upload-file.ts index 24da15d3..7d69bfe7 100644 --- a/api/ipfs/upload-file.ts +++ b/api/ipfs/upload-file.ts @@ -4,6 +4,7 @@ import { isRateLimited } from '../_lib/rateLimit' import { PINATA_API_URL, pinataHeaders } from '../_lib/pinata' import { validateFileMagicBytes } from '../_lib/fileValidation' import { verifyToken } from '../_lib/jwt' +import { recordPinOwner } from '../_lib/pinOwnership' // Kept just under Vercel's 4.5MB serverless function request-body ceiling. const MAX_FILE_SIZE = 4 * 1024 * 1024 @@ -143,6 +144,13 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const data = (await pinataRes.json()) as { IpfsHash: string } + + try { + await recordPinOwner(data.IpfsHash, walletAddress) + } catch (err) { + console.error('Failed to record pin owner:', err) + } + res.status(200).json({ cid: data.IpfsHash }) } catch { res.status(500).json({ error: 'Unexpected error while uploading to IPFS.' }) diff --git a/api/ipfs/upload-json.ts b/api/ipfs/upload-json.ts index e215b0c9..1565074a 100644 --- a/api/ipfs/upload-json.ts +++ b/api/ipfs/upload-json.ts @@ -3,6 +3,7 @@ import { isRateLimited } from '../_lib/rateLimit' import { PINATA_API_URL, pinataHeaders } from '../_lib/pinata' import { validateTokenMetadata } from '../_lib/schemaValidation' import { verifyToken } from '../_lib/jwt' +import { recordPinOwner } from '../_lib/pinOwnership' interface UploadJsonBody { metadata: unknown @@ -49,7 +50,9 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { typeof body.metadata !== 'object' || body.metadata === null ) { - res.status(400).json({ error: 'Request body must include { metadata: object, name: string }.' }) + res.status(400).json({ + error: 'Request body must include { metadata: object, name: string }.', + }) return } @@ -66,7 +69,9 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { try { headers = pinataHeaders({ 'Content-Type': 'application/json' }) } catch (err) { - res.status(500).json({ error: err instanceof Error ? err.message : 'Server misconfiguration.' }) + res.status(500).json({ + error: err instanceof Error ? err.message : 'Server misconfiguration.', + }) return } @@ -87,6 +92,13 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const data = (await pinataRes.json()) as { IpfsHash: string } + + try { + await recordPinOwner(data.IpfsHash, walletAddress) + } catch (err) { + console.error('Failed to record pin owner:', err) + } + res.status(200).json({ cid: data.IpfsHash }) } catch { res.status(500).json({ error: 'Unexpected error while uploading metadata to IPFS.' }) diff --git a/contracts/token-factory/src/lib.rs b/contracts/token-factory/src/lib.rs index 9dcc71f5..047b0da9 100644 --- a/contracts/token-factory/src/lib.rs +++ b/contracts/token-factory/src/lib.rs @@ -210,13 +210,13 @@ pub enum Error { /// this is a hard error that aborts the call. TreasuryTransferFailed = 24, /// `create_tokens_batch` batch size exceeds `MAX_BATCH_SIZE` - BatchSizeExceeded = 24, + BatchSizeExceeded = 25, /// `accept_admin` called when no proposal is pending, or the proposed /// address does not match the caller - NoPendingProposal = 24, + NoPendingProposal = 26, /// The pending admin proposal has passed its expiry ledger and can no /// longer be accepted; the current admin must open a new proposal - ProposalExpired = 25, + ProposalExpired = 27, } #[contract] @@ -462,16 +462,14 @@ impl TokenFactory { let mut treasury_extra: i128 = remainder; // any unassigned rounding remainder for i in 0..n { if let (Ok(Some(addr)), Ok(Some(share))) = (addrs.try_get(i), floors.try_get(i)) { - if share > 0 { - if fee_client.try_transfer(payer, &addr, &share).is_err() { - treasury_extra = treasury_extra - .checked_add(share) - .ok_or(Error::ArithmeticOverflow)?; - env.events().publish( - (symbol_short!("factory"), symbol_short!("fee_redir")), - (addr, share), - ); - } + if share > 0 && fee_client.try_transfer(payer, &addr, &share).is_err() { + treasury_extra = treasury_extra + .checked_add(share) + .ok_or(Error::ArithmeticOverflow)?; + env.events().publish( + (symbol_short!("factory"), symbol_short!("fee_redir")), + (addr, share), + ); } } } @@ -485,7 +483,10 @@ impl TokenFactory { { return Err(Error::TreasuryTransferFailed); } - } else if fee_client.try_transfer(payer, &state.treasury, &amount).is_err() { + } else if fee_client + .try_transfer(payer, &state.treasury, &amount) + .is_err() + { return Err(Error::TreasuryTransferFailed); } Ok(()) @@ -1603,6 +1604,15 @@ impl TokenFactory { } } + // The v3 walk is chunked, so it may still be mid-flight here. Every + // later step must wait: bumping the version marker past 3 would make + // the next `migrate` call skip the v3 block entirely and strand the + // `TokenInfo` entries beyond the cursor in `instance` storage forever. + // Return successfully so the caller simply calls `migrate` again. + if on_chain_version < 3 { + return Ok(()); + } + // Each future migration step follows the same pattern: // // if on_chain_version < N { @@ -1705,7 +1715,11 @@ impl TokenFactory { /// Does **not** complete the rotation — only `accept_admin` does that. /// There is no single-step rotation path: `transfer_admin` and /// `update_admin` both delegate here. - pub fn propose_admin(env: Env, current_admin: Address, new_admin: Address) -> Result<(), Error> { + pub fn propose_admin( + env: Env, + current_admin: Address, + new_admin: Address, + ) -> Result<(), Error> { current_admin.require_auth(); let mut state = Self::load_state(&env)?; if state.admin != current_admin { @@ -1752,14 +1766,19 @@ impl TokenFactory { if proposed != new_admin { return Err(Error::NoPendingProposal); } - let expiry = state.pending_admin_expiry.take().unwrap_or(0); - // Clear the proposal now — whether expired or accepted we don't want it live. - state.pending_admin = None; + let expiry = state.pending_admin_expiry.unwrap_or(0); if (env.ledger().sequence() as u64) >= expiry { - // Proposal expired — clear it and report. - Self::save_state(&env, &state); + // Returning an error reverts the whole invocation, so an expired + // proposal cannot be cleared from here — any write we made would + // be rolled back with the rest of the call. It simply stays on + // record as inert: it can never be accepted, and the current + // admin removes it with `cancel_admin_proposal` or replaces it by + // calling `propose_admin` again. return Err(Error::ProposalExpired); } + // Accepted — the proposal is consumed. + state.pending_admin = None; + state.pending_admin_expiry = None; let old_admin = state.admin.clone(); state.admin = new_admin.clone(); Self::save_state(&env, &state); diff --git a/contracts/token-factory/src/test.rs b/contracts/token-factory/src/test.rs index 3c8834e6..bb9d71a9 100644 --- a/contracts/token-factory/src/test.rs +++ b/contracts/token-factory/src/test.rs @@ -5,7 +5,7 @@ extern crate std; use super::*; use soroban_sdk::{ contract, contractimpl, - testutils::{Address as _, Events as _}, + testutils::{Address as _, Events as _, Ledger as _}, token::{StellarAssetClient, TokenClient}, Address, BytesN, Env, Map, MuxedAddress, String, }; @@ -1783,17 +1783,28 @@ fn test_expired_proposal_cannot_be_accepted() { // Advance the ledger past the TTL. s.env.ledger().with_mut(|li| { - li.sequence_number = li.sequence_number.saturating_add(ADMIN_PROPOSAL_TTL_LEDGERS as u32 + 1); + li.sequence_number = li + .sequence_number + .saturating_add(ADMIN_PROPOSAL_TTL_LEDGERS as u32 + 1); }); assert_eq!( s.client.try_accept_admin(&new_admin), Err(Ok(Error::ProposalExpired)) ); - // After expiry the state must be cleared so the admin can propose again. + // The rejection reverts the whole call, so the expired proposal is still + // on record — inert, never acceptable, and harmless. The admin clears it + // by cancelling, or replaces it by proposing again. let state = s.client.get_state(); - assert_eq!(state.pending_admin, None); + assert_eq!(state.pending_admin, Some(new_admin.clone())); assert_eq!(state.admin, s.admin); + + // Re-proposing overwrites the expired entry with a fresh expiry window, + // and the new proposal is acceptable. + s.client.propose_admin(&s.admin, &new_admin); + s.client.accept_admin(&new_admin); + assert_eq!(s.client.get_state().admin, new_admin); + assert_eq!(s.client.get_state().pending_admin, None); } #[test] diff --git a/contracts/token-factory/test_snapshots/test/test_accept_admin_completes_rotation.1.json b/contracts/token-factory/test_snapshots/test/test_accept_admin_completes_rotation.1.json new file mode 100644 index 00000000..0fdd6ebb --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_accept_admin_completes_rotation.1.json @@ -0,0 +1,481 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_accept_admin_old_admin_loses_access.1.json b/contracts/token-factory/test_snapshots/test/test_accept_admin_old_admin_loses_access.1.json new file mode 100644 index 00000000..09100a44 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_accept_admin_old_admin_loses_access.1.json @@ -0,0 +1,521 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "pause", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4270020994084947596" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_accept_admin_with_no_proposal_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_accept_admin_with_no_proposal_rejected.1.json new file mode 100644 index 00000000..da796622 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_accept_admin_with_no_proposal_rejected.1.json @@ -0,0 +1,400 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_accept_admin_wrong_address_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_accept_admin_wrong_address_rejected.1.json new file mode 100644 index 00000000..328f6b6d --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_accept_admin_wrong_address_rejected.1.json @@ -0,0 +1,447 @@ +{ + "generators": { + "address": 6, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": { + "u64": "17280" + } + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_succeeds_and_persists.1.json b/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_succeeds_and_persists.1.json index 1e528f74..51445821 100644 --- a/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_succeeds_and_persists.1.json +++ b/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_succeeds_and_persists.1.json @@ -221,7 +221,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -282,12 +282,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_unauthorized.1.json index 879e51a4..14a8fb0c 100644 --- a/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_add_to_whitelist_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_admin_can_pause_and_unpause.1.json b/contracts/token-factory/test_snapshots/test/test_admin_can_pause_and_unpause.1.json index df5206e5..4ba486f7 100644 --- a/contracts/token-factory/test_snapshots/test/test_admin_can_pause_and_unpause.1.json +++ b/contracts/token-factory/test_snapshots/test/test_admin_can_pause_and_unpause.1.json @@ -231,7 +231,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -292,12 +292,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_allows_headroom_mint.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_allows_headroom_mint.1.json index 886d78b9..03abf737 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_allows_headroom_mint.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_allows_headroom_mint.1.json @@ -650,7 +650,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -711,12 +711,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_cannot_be_applied_twice.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_cannot_be_applied_twice.1.json index f8d76e77..236f150a 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_cannot_be_applied_twice.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_cannot_be_applied_twice.1.json @@ -539,7 +539,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -600,12 +600,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_token_without_cap.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_token_without_cap.1.json index 2ec71cfe..a33181fa 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_token_without_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_token_without_cap.1.json @@ -438,7 +438,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -499,12 +499,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_value_above_cap.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_value_above_cap.1.json index d9c71753..2e1f962b 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_value_above_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_rejects_value_above_cap.1.json @@ -440,7 +440,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -501,12 +501,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_seeds_untracked_cap.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_seeds_untracked_cap.1.json index 5bd8f4bf..2b0455f2 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_seeds_untracked_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_seeds_untracked_cap.1.json @@ -581,7 +581,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -642,12 +642,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_unauthorized.1.json index 24c3ad0b..e3fe9663 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_capped_supply_unauthorized.1.json @@ -440,7 +440,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -501,12 +501,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_cannot_hijack_another_index.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_cannot_hijack_another_index.1.json index 64aa9e8f..96b79062 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_cannot_hijack_another_index.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_cannot_hijack_another_index.1.json @@ -671,7 +671,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -732,12 +732,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_is_idempotent.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_is_idempotent.1.json index 2ad22966..d8d326a9 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_is_idempotent.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_is_idempotent.1.json @@ -442,7 +442,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -503,12 +503,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_rejects_unregistered_address.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_rejects_unregistered_address.1.json index 101a980a..ba9a9cc9 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_rejects_unregistered_address.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_rejects_unregistered_address.1.json @@ -213,7 +213,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -274,12 +274,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_repairs_a_pre_existing_token.1.json b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_repairs_a_pre_existing_token.1.json index 2ad22966..d8d326a9 100644 --- a/contracts/token-factory/test_snapshots/test/test_backfill_token_address_repairs_a_pre_existing_token.1.json +++ b/contracts/token-factory/test_snapshots/test/test_backfill_token_address_repairs_a_pre_existing_token.1.json @@ -442,7 +442,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -503,12 +503,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_not_whitelisted.1.json b/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_not_whitelisted.1.json index 36e1aba0..a28800c1 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_not_whitelisted.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_not_whitelisted.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_paused.1.json b/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_paused.1.json index ae773042..6cba0d2c 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_paused.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_blocked_when_paused.1.json @@ -191,7 +191,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -252,12 +252,24 @@ "bool": true } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_empty_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_batch_empty_rejected.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_empty_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_empty_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_insufficient_fee_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_batch_insufficient_fee_rejected.1.json index ea5a7e89..d546880f 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_insufficient_fee_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_insufficient_fee_rejected.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_invalid_name_rejects_entire_batch.1.json b/contracts/token-factory/test_snapshots/test/test_batch_invalid_name_rejects_entire_batch.1.json index 132bf828..567c4987 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_invalid_name_rejects_entire_batch.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_invalid_name_rejects_entire_batch.1.json @@ -195,7 +195,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -256,12 +256,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_reentrancy_guard.1.json b/contracts/token-factory/test_snapshots/test/test_batch_reentrancy_guard.1.json index 9d36a82f..6458358a 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_reentrancy_guard.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_reentrancy_guard.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_batch_whitelisted_creator_passes_whitelist_gate.1.json b/contracts/token-factory/test_snapshots/test/test_batch_whitelisted_creator_passes_whitelist_gate.1.json index 81063008..03e0f283 100644 --- a/contracts/token-factory/test_snapshots/test/test_batch_whitelisted_creator_passes_whitelist_gate.1.json +++ b/contracts/token-factory/test_snapshots/test/test_batch_whitelisted_creator_passes_whitelist_gate.1.json @@ -263,7 +263,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -324,12 +324,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn.1.json b/contracts/token-factory/test_snapshots/test/test_burn.1.json index 625d369f..9960ce81 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn.1.json @@ -503,7 +503,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -564,12 +564,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_allowed_when_factory_paused.1.json b/contracts/token-factory/test_snapshots/test/test_burn_allowed_when_factory_paused.1.json index 2ecd6659..42c3d260 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_allowed_when_factory_paused.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_allowed_when_factory_paused.1.json @@ -542,7 +542,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -603,12 +603,24 @@ "bool": true } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_amount_exceeds_balance.1.json b/contracts/token-factory/test_snapshots/test/test_burn_amount_exceeds_balance.1.json index e5f770a9..db6a4fe9 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_amount_exceeds_balance.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_amount_exceeds_balance.1.json @@ -460,7 +460,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -521,12 +521,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_disabled.1.json b/contracts/token-factory/test_snapshots/test/test_burn_disabled.1.json index a3584c9e..926f95e4 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_disabled.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_disabled.1.json @@ -460,7 +460,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -521,12 +521,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_disabled_no_bypass.1.json b/contracts/token-factory/test_snapshots/test/test_burn_disabled_no_bypass.1.json index 6c2a83e6..d7bdd728 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_disabled_no_bypass.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_disabled_no_bypass.1.json @@ -461,7 +461,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -522,12 +522,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_event_only_emitted_for_factory_token.1.json b/contracts/token-factory/test_snapshots/test/test_burn_event_only_emitted_for_factory_token.1.json index 9f3ff0ec..5b18261e 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_event_only_emitted_for_factory_token.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_event_only_emitted_for_factory_token.1.json @@ -587,7 +587,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -648,12 +648,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_exact_balance.1.json b/contracts/token-factory/test_snapshots/test/test_burn_exact_balance.1.json index 6eccc276..920eca46 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_exact_balance.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_exact_balance.1.json @@ -503,7 +503,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -564,12 +564,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_invalid_amount_zero.1.json b/contracts/token-factory/test_snapshots/test/test_burn_invalid_amount_zero.1.json index 101a980a..ba9a9cc9 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_invalid_amount_zero.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_invalid_amount_zero.1.json @@ -213,7 +213,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -274,12 +274,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_lock_released_after_success.1.json b/contracts/token-factory/test_snapshots/test/test_burn_lock_released_after_success.1.json index 0f1d9d22..4e4f1c65 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_lock_released_after_success.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_lock_released_after_success.1.json @@ -503,7 +503,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -564,12 +564,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_reentrancy_guard.1.json b/contracts/token-factory/test_snapshots/test/test_burn_reentrancy_guard.1.json index 321376fd..d617630a 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_reentrancy_guard.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_reentrancy_guard.1.json @@ -461,7 +461,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -522,12 +522,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_registered_index_missing_info_fails.1.json b/contracts/token-factory/test_snapshots/test/test_burn_registered_index_missing_info_fails.1.json index 44fd928a..b7c64e2a 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_registered_index_missing_info_fails.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_registered_index_missing_info_fails.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_burn_unregistered_token_fails.1.json b/contracts/token-factory/test_snapshots/test/test_burn_unregistered_token_fails.1.json index dd88b33c..c693b2b1 100644 --- a/contracts/token-factory/test_snapshots/test/test_burn_unregistered_token_fails.1.json +++ b/contracts/token-factory/test_snapshots/test/test_burn_unregistered_token_fails.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal.1.json b/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal.1.json new file mode 100644 index 00000000..293e5415 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal.1.json @@ -0,0 +1,481 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "cancel_admin_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal_idempotent.1.json b/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal_idempotent.1.json new file mode 100644 index 00000000..5ddcc9d5 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal_idempotent.1.json @@ -0,0 +1,438 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "cancel_admin_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal_unauthorized.1.json new file mode 100644 index 00000000..328f6b6d --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_cancel_admin_proposal_unauthorized.1.json @@ -0,0 +1,447 @@ +{ + "generators": { + "address": 6, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": { + "u64": "17280" + } + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_allowed_when_whitelist_disabled.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_allowed_when_whitelist_disabled.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_allowed_when_whitelist_disabled.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_allowed_when_whitelist_disabled.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_not_whitelisted.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_not_whitelisted.1.json index 25990886..e8ed2235 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_not_whitelisted.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_not_whitelisted.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_paused.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_paused.1.json index ae773042..6cba0d2c 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_paused.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_blocked_when_paused.1.json @@ -191,7 +191,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -252,12 +252,24 @@ "bool": true } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_insufficient_fee.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_insufficient_fee.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_insufficient_fee.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_insufficient_fee.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals_large.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals_large.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals_large.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_decimals_large.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_name_empty.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_name_empty.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_name_empty.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_name_empty.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_symbol_empty.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_symbol_empty.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_invalid_symbol_empty.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_invalid_symbol_empty.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_max_supply_below_initial_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_max_supply_below_initial_rejected.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_max_supply_below_initial_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_max_supply_below_initial_rejected.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_min_supply_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_min_supply_rejected.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_min_supply_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_min_supply_rejected.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_negative_supply_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_negative_supply_rejected.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_negative_supply_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_negative_supply_rejected.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_nonpositive_max_supply_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_nonpositive_max_supply_rejected.1.json index 5caa94fa..b0e1b6c0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_nonpositive_max_supply_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_nonpositive_max_supply_rejected.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_overflow_protection.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_overflow_protection.1.json index 8137187d..b76b44e9 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_overflow_protection.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_overflow_protection.1.json @@ -195,7 +195,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -256,12 +256,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_reentrancy_guard.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_reentrancy_guard.1.json index 9d36a82f..6458358a 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_reentrancy_guard.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_reentrancy_guard.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_supply_i128_max_passes_validation.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_supply_i128_max_passes_validation.1.json index 2bd871e1..588696d0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_supply_i128_max_passes_validation.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_supply_i128_max_passes_validation.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_supply_zero_passes_validation.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_supply_zero_passes_validation.1.json index 2bd871e1..588696d0 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_supply_zero_passes_validation.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_supply_zero_passes_validation.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_token_whitelisted_creator_passes_whitelist_gate.1.json b/contracts/token-factory/test_snapshots/test/test_create_token_whitelisted_creator_passes_whitelist_gate.1.json index 81063008..03e0f283 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_token_whitelisted_creator_passes_whitelist_gate.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_token_whitelisted_creator_passes_whitelist_gate.1.json @@ -263,7 +263,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -324,12 +324,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_create_tokens_batch_overflow_protection_upfront.1.json b/contracts/token-factory/test_snapshots/test/test_create_tokens_batch_overflow_protection_upfront.1.json index c8e774a9..98e94ae7 100644 --- a/contracts/token-factory/test_snapshots/test/test_create_tokens_batch_overflow_protection_upfront.1.json +++ b/contracts/token-factory/test_snapshots/test/test_create_tokens_batch_overflow_protection_upfront.1.json @@ -197,7 +197,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -258,12 +258,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_cross_function_reentrancy_lock_blocks_all_entrypoints.1.json b/contracts/token-factory/test_snapshots/test/test_cross_function_reentrancy_lock_blocks_all_entrypoints.1.json index 32b1569a..75ca8be9 100644 --- a/contracts/token-factory/test_snapshots/test/test_cross_function_reentrancy_lock_blocks_all_entrypoints.1.json +++ b/contracts/token-factory/test_snapshots/test/test_cross_function_reentrancy_lock_blocks_all_entrypoints.1.json @@ -508,7 +508,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -569,12 +569,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_expired_proposal_cannot_be_accepted.1.json b/contracts/token-factory/test_snapshots/test/test_expired_proposal_cannot_be_accepted.1.json new file mode 100644 index 00000000..59598cd2 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_expired_proposal_cannot_be_accepted.1.json @@ -0,0 +1,526 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 17281, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6329280 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4270020994084947596" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6329280 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_fee_distributed_according_to_split.1.json b/contracts/token-factory/test_snapshots/test/test_fee_distributed_according_to_split.1.json index 2cedddeb..29bb33c6 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_distributed_according_to_split.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_distributed_according_to_split.1.json @@ -654,7 +654,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -715,12 +715,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_goes_to_treasury_when_no_split.1.json b/contracts/token-factory/test_snapshots/test/test_fee_goes_to_treasury_when_no_split.1.json index a7a4006f..4f66697e 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_goes_to_treasury_when_no_split.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_goes_to_treasury_when_no_split.1.json @@ -549,7 +549,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -610,12 +610,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_split_largest_remainder_dust_fee.1.json b/contracts/token-factory/test_snapshots/test/test_fee_split_largest_remainder_dust_fee.1.json index 276abd21..710ba837 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_split_largest_remainder_dust_fee.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_split_largest_remainder_dust_fee.1.json @@ -697,7 +697,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -758,12 +758,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_split_max_recipients_conservation.1.json b/contracts/token-factory/test_snapshots/test/test_fee_split_max_recipients_conservation.1.json index 1c0de807..75dbb447 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_split_max_recipients_conservation.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_split_max_recipients_conservation.1.json @@ -994,7 +994,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -1055,12 +1055,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_split_odd_amount_remainder_goes_to_treasury.1.json b/contracts/token-factory/test_snapshots/test/test_fee_split_odd_amount_remainder_goes_to_treasury.1.json index 30477951..fd15a0d8 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_split_odd_amount_remainder_goes_to_treasury.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_split_odd_amount_remainder_goes_to_treasury.1.json @@ -698,7 +698,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -759,12 +759,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_split_sum_invariant_many_recipients.1.json b/contracts/token-factory/test_snapshots/test/test_fee_split_sum_invariant_many_recipients.1.json index a88850e2..495130e7 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_split_sum_invariant_many_recipients.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_split_sum_invariant_many_recipients.1.json @@ -808,7 +808,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -869,12 +869,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_split_zero_share_recipient_skipped_remainder_to_treasury.1.json b/contracts/token-factory/test_snapshots/test/test_fee_split_zero_share_recipient_skipped_remainder_to_treasury.1.json index 3bf7ca0d..eb5e3dff 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_split_zero_share_recipient_skipped_remainder_to_treasury.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_split_zero_share_recipient_skipped_remainder_to_treasury.1.json @@ -678,7 +678,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -739,12 +739,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_fee_update_race_rejects_with_no_partial_transfer.1.json b/contracts/token-factory/test_snapshots/test/test_fee_update_race_rejects_with_no_partial_transfer.1.json index 6ce329d5..fef03f19 100644 --- a/contracts/token-factory/test_snapshots/test/test_fee_update_race_rejects_with_no_partial_transfer.1.json +++ b/contracts/token-factory/test_snapshots/test/test_fee_update_race_rejects_with_no_partial_transfer.1.json @@ -526,7 +526,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -587,12 +587,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_freeze_metadata_idempotent.1.json b/contracts/token-factory/test_snapshots/test/test_freeze_metadata_idempotent.1.json index d36d1fb1..506850c6 100644 --- a/contracts/token-factory/test_snapshots/test/test_freeze_metadata_idempotent.1.json +++ b/contracts/token-factory/test_snapshots/test/test_freeze_metadata_idempotent.1.json @@ -509,7 +509,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -570,12 +570,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_freeze_metadata_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_freeze_metadata_unauthorized.1.json index e19c4314..800477e3 100644 --- a/contracts/token-factory/test_snapshots/test/test_freeze_metadata_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_freeze_metadata_unauthorized.1.json @@ -438,7 +438,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -499,12 +499,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_metadata_none_before_set_then_some_after.1.json b/contracts/token-factory/test_snapshots/test/test_get_metadata_none_before_set_then_some_after.1.json index a6935d22..30904828 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_metadata_none_before_set_then_some_after.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_metadata_none_before_set_then_some_after.1.json @@ -440,7 +440,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -516,12 +516,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_address_enumerates_full_token_set.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_address_enumerates_full_token_set.1.json index 1f061d8b..003dcefb 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_address_enumerates_full_token_set.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_address_enumerates_full_token_set.1.json @@ -1355,7 +1355,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -1416,12 +1416,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_address_round_trips_with_get_token_index.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_address_round_trips_with_get_token_index.1.json index 6fdf0579..5a284671 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_address_round_trips_with_get_token_index.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_address_round_trips_with_get_token_index.1.json @@ -439,7 +439,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -500,12 +500,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_address_unknown_index_returns_not_found.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_address_unknown_index_returns_not_found.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_address_unknown_index_returns_not_found.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_address_unknown_index_returns_not_found.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_index_not_found_for_unregistered_address.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_index_not_found_for_unregistered_address.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_index_not_found_for_unregistered_address.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_index_not_found_for_unregistered_address.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_index_resolves_registered_address.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_index_resolves_registered_address.1.json index 2ec71cfe..a33181fa 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_index_resolves_registered_address.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_index_resolves_registered_address.1.json @@ -438,7 +438,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -499,12 +499,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_info.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_info.1.json index 2cce96fa..f3035a72 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_info.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_info.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_missing_info_entry.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_missing_info_entry.1.json index ace28538..447cd6b5 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_missing_info_entry.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_missing_info_entry.1.json @@ -214,7 +214,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -275,12 +275,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_not_found.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_not_found.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_not_found.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_not_found.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_returns_authoritative_identity.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_returns_authoritative_identity.1.json index 7ae4d840..2236acee 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_returns_authoritative_identity.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_info_by_address_returns_authoritative_identity.1.json @@ -214,7 +214,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -275,12 +275,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_token_info_not_found.1.json b/contracts/token-factory/test_snapshots/test/test_get_token_info_not_found.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_token_info_not_found.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_token_info_not_found.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator.1.json index d96d7e2f..48843fb9 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator.1.json @@ -666,7 +666,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -727,12 +727,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_clamps_oversized_limit.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_clamps_oversized_limit.1.json index 7e1a54da..826dd062 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_clamps_oversized_limit.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_clamps_oversized_limit.1.json @@ -13922,7 +13922,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -13983,12 +13983,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_empty_for_unknown.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_empty_for_unknown.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_empty_for_unknown.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_empty_for_unknown.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_first_page.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_first_page.1.json index 3503cf76..5558339a 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_first_page.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_first_page.1.json @@ -3631,7 +3631,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -3692,12 +3692,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_isolated_per_creator.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_isolated_per_creator.1.json index 90c0715d..4dbe025f 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_isolated_per_creator.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_isolated_per_creator.1.json @@ -2779,7 +2779,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -2840,12 +2840,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_offset_past_end.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_offset_past_end.1.json index f85af7eb..1c57d451 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_offset_past_end.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_offset_past_end.1.json @@ -1352,7 +1352,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -1413,12 +1413,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_partial_last_page.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_partial_last_page.1.json index ffe74e52..d68daf4d 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_partial_last_page.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_partial_last_page.1.json @@ -1810,7 +1810,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -1871,12 +1871,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_second_page.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_second_page.1.json index 3503cf76..5558339a 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_second_page.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_second_page.1.json @@ -3631,7 +3631,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -3692,12 +3692,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_zero_limit.1.json b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_zero_limit.1.json index 409e6ac9..d196f532 100644 --- a/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_zero_limit.1.json +++ b/contracts/token-factory/test_snapshots/test/test_get_tokens_by_creator_zero_limit.1.json @@ -895,7 +895,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -956,12 +956,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_initialize.1.json b/contracts/token-factory/test_snapshots/test/test_initialize.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_initialize.1.json +++ b/contracts/token-factory/test_snapshots/test/test_initialize.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_initialize_already_initialized.1.json b/contracts/token-factory/test_snapshots/test/test_initialize_already_initialized.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_initialize_already_initialized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_initialize_already_initialized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_initialize_sets_schema_version.1.json b/contracts/token-factory/test_snapshots/test/test_initialize_sets_schema_version.1.json index 8fdd471f..4cf9b07d 100644 --- a/contracts/token-factory/test_snapshots/test/test_initialize_sets_schema_version.1.json +++ b/contracts/token-factory/test_snapshots/test/test_initialize_sets_schema_version.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_initialize_sets_whitelist_enabled_false.1.json b/contracts/token-factory/test_snapshots/test/test_initialize_sets_whitelist_enabled_false.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_initialize_sets_whitelist_enabled_false.1.json +++ b/contracts/token-factory/test_snapshots/test/test_initialize_sets_whitelist_enabled_false.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_initialize_zero_fees_allowed.1.json b/contracts/token-factory/test_snapshots/test/test_initialize_zero_fees_allowed.1.json index 184e71a1..2f234cb1 100644 --- a/contracts/token-factory/test_snapshots/test/test_initialize_zero_fees_allowed.1.json +++ b/contracts/token-factory/test_snapshots/test/test_initialize_zero_fees_allowed.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_instance_storage_size_stays_flat_under_load.1.json b/contracts/token-factory/test_snapshots/test/test_instance_storage_size_stays_flat_under_load.1.json index 5e5f2b30..0ead02b4 100644 --- a/contracts/token-factory/test_snapshots/test/test_instance_storage_size_stays_flat_under_load.1.json +++ b/contracts/token-factory/test_snapshots/test/test_instance_storage_size_stays_flat_under_load.1.json @@ -68769,7 +68769,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -68830,12 +68830,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_after_remove.1.json b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_after_remove.1.json index 46cb5a80..84d60065 100644 --- a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_after_remove.1.json +++ b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_after_remove.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_for_unknown.1.json b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_for_unknown.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_for_unknown.1.json +++ b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_false_for_unknown.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_true_after_add.1.json b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_true_after_add.1.json index 1e528f74..51445821 100644 --- a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_true_after_add.1.json +++ b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_returns_true_after_add.1.json @@ -221,7 +221,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -282,12 +282,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_view_agrees_with_creation_gate.1.json b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_view_agrees_with_creation_gate.1.json index 09053383..e5c0a3f1 100644 --- a/contracts/token-factory/test_snapshots/test/test_is_whitelisted_view_agrees_with_creation_gate.1.json +++ b/contracts/token-factory/test_snapshots/test/test_is_whitelisted_view_agrees_with_creation_gate.1.json @@ -325,7 +325,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -386,12 +386,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_from_v0_walks_all_steps_to_v4.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_from_v0_walks_all_steps_to_v4.1.json new file mode 100644 index 00000000..f8f058bc --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_migrate_from_v0_walks_all_steps_to_v4.1.json @@ -0,0 +1,448 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "migrate", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "mig3cur" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_from_version_0_walks_all_steps.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_from_version_0_walks_all_steps.1.json index b58e4f4d..da58e82c 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_from_version_0_walks_all_steps.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_from_version_0_walks_all_steps.1.json @@ -202,7 +202,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -263,12 +263,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_from_version_1_walks_remaining_steps.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_from_version_1_walks_remaining_steps.1.json index 1df024a1..dea6e048 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_from_version_1_walks_remaining_steps.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_from_version_1_walks_remaining_steps.1.json @@ -201,7 +201,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -262,12 +262,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_is_idempotent.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_is_idempotent.1.json index 85331122..9217c6a2 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_is_idempotent.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_is_idempotent.1.json @@ -230,7 +230,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -291,12 +291,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_preserves_state_fields.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_preserves_state_fields.1.json index bc1da95c..f0a9ca64 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_preserves_state_fields.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_preserves_state_fields.1.json @@ -191,7 +191,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -252,12 +252,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_preserves_whitelist_enabled_flag.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_preserves_whitelist_enabled_flag.1.json index 83804984..b924d465 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_preserves_whitelist_enabled_flag.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_preserves_whitelist_enabled_flag.1.json @@ -233,7 +233,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -294,12 +294,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_unauthorized.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_upgrades_pre_versioned_state.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_upgrades_pre_versioned_state.1.json index 1df024a1..dea6e048 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_upgrades_pre_versioned_state.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_upgrades_pre_versioned_state.1.json @@ -201,7 +201,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -262,12 +262,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v1_to_v3_sets_whitelist_enabled_false.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v1_to_v3_sets_whitelist_enabled_false.1.json index 1df024a1..dea6e048 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_v1_to_v3_sets_whitelist_enabled_false.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v1_to_v3_sets_whitelist_enabled_false.1.json @@ -201,7 +201,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -262,12 +262,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v2_idempotent_at_current_version.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v2_idempotent_at_current_version.1.json index 7b865de2..762270f0 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_v2_idempotent_at_current_version.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v2_idempotent_at_current_version.1.json @@ -232,7 +232,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -293,12 +293,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_across_repeated_calls.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_across_repeated_calls.1.json index 184e6102..969202e2 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_across_repeated_calls.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_across_repeated_calls.1.json @@ -5199,7 +5199,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -5260,12 +5260,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_in_one_call_when_small.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_in_one_call_when_small.1.json index 2117d827..296560df 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_in_one_call_when_small.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v3_completes_in_one_call_when_small.1.json @@ -446,7 +446,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -507,12 +507,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v3_does_not_complete_in_one_chunk_when_oversized.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v3_does_not_complete_in_one_chunk_when_oversized.1.json index a5619505..5d29b778 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_v3_does_not_complete_in_one_chunk_when_oversized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v3_does_not_complete_in_one_chunk_when_oversized.1.json @@ -1902,6 +1902,18 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v3_to_v4_adds_pending_admin_fields.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v3_to_v4_adds_pending_admin_fields.1.json new file mode 100644 index 00000000..d29c4c8d --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v3_to_v4_adds_pending_admin_fields.1.json @@ -0,0 +1,440 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "migrate", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_v4_idempotent_for_pending_admin.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_v4_idempotent_for_pending_admin.1.json new file mode 100644 index 00000000..9217c6a2 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_migrate_v4_idempotent_for_pending_admin.1.json @@ -0,0 +1,478 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "migrate", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "migrate", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_migrate_whitelist_step_is_idempotent.1.json b/contracts/token-factory/test_snapshots/test/test_migrate_whitelist_step_is_idempotent.1.json index 58c8a381..232faacc 100644 --- a/contracts/token-factory/test_snapshots/test/test_migrate_whitelist_step_is_idempotent.1.json +++ b/contracts/token-factory/test_snapshots/test/test_migrate_whitelist_step_is_idempotent.1.json @@ -231,7 +231,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -292,12 +292,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens.1.json index edcd9e75..9ad0ccb2 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens.1.json @@ -549,7 +549,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -610,12 +610,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_exactly_at_cap.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_exactly_at_cap.1.json index f8319324..0b5052e0 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_exactly_at_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_exactly_at_cap.1.json @@ -647,7 +647,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -708,12 +708,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_exceeds_cap.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_exceeds_cap.1.json index 1bfa31cb..a830d135 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_exceeds_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_exceeds_cap.1.json @@ -482,7 +482,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -543,12 +543,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_fee_split_sums_to_charged_fee_not_payment.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_fee_split_sums_to_charged_fee_not_payment.1.json index 3e88247d..477d155f 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_fee_split_sums_to_charged_fee_not_payment.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_fee_split_sums_to_charged_fee_not_payment.1.json @@ -656,7 +656,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -717,12 +717,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_insufficient_fee.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_insufficient_fee.1.json index f38149d5..d1791606 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_insufficient_fee.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_insufficient_fee.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_error.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_error.1.json index 1d96af2a..80dfd5fa 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_error.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_error.1.json @@ -439,7 +439,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -500,12 +500,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_success.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_success.1.json index a7a4006f..4f66697e 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_success.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_lock_released_after_success.1.json @@ -549,7 +549,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -610,12 +610,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_one_over_cap.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_one_over_cap.1.json index e8977ad1..d1d0867d 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_one_over_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_one_over_cap.1.json @@ -578,7 +578,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -639,12 +639,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_overpayment_charges_exact_fee_only.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_overpayment_charges_exact_fee_only.1.json index 215fdec9..2b5195da 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_overpayment_charges_exact_fee_only.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_overpayment_charges_exact_fee_only.1.json @@ -551,7 +551,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -612,12 +612,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_reentrancy_guard.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_reentrancy_guard.1.json index f1c6e104..4cb6d7a7 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_reentrancy_guard.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_reentrancy_guard.1.json @@ -481,7 +481,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -542,12 +542,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_rejects_real_reentrant_call.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_rejects_real_reentrant_call.1.json new file mode 100644 index 00000000..fc1525c9 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_rejects_real_reentrant_call.1.json @@ -0,0 +1,795 @@ +{ + "generators": { + "address": 6, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7NV", + { + "function": { + "contract_fn": { + "contract_address": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "function_name": "mint_tokens", + "args": [ + { + "address": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + }, + { + "i128": "100" + }, + { + "i128": "1000" + } + ] + } + }, + "sub_invocations": [ + { + "function": { + "contract_fn": { + "contract_address": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG", + "function_name": "mint", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + }, + { + "i128": "100" + } + ] + } + }, + "sub_invocations": [] + } + ] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7NV", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7NV", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "CreatorTokenCount" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "CreatorTokens" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "u32": 0 + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u32": 1 + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "TokenAddress" + }, + { + "u32": 1 + } + ] + }, + "durability": "persistent", + "val": { + "address": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG" + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "TokenIndex" + }, + { + "address": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "TokenInfo" + }, + { + "u32": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "burn_enabled" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "creator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "decimals" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "max_supply" + }, + "val": "void" + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "T" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "T" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "address": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG" + }, + { + "symbol": "owner" + } + ] + }, + "durability": "persistent", + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "attacker" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "blocked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "factory" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "amount" + }, + "val": { + "i128": "100" + } + }, + { + "key": { + "symbol": "authorized" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "clawback" + }, + "val": { + "bool": false + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 518400 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CDLDVFKHEZ2RVB3NG4UQA4VPD3TSHV6XMHXMHP2BSGCJ2IIWVTOHGDSG", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7NV" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000005" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_unauthorized.1.json index b87cbd44..9241f07f 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_unauthorized.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_unregistered_token_fails.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_unregistered_token_fails.1.json index 56dbaa65..3041e3f7 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_unregistered_token_fails.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_unregistered_token_fails.1.json @@ -255,7 +255,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -316,12 +316,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_within_cap.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_within_cap.1.json index b6f28300..ac83d789 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_within_cap.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_within_cap.1.json @@ -578,7 +578,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -639,12 +639,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_mint_tokens_zero_amount_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_mint_tokens_zero_amount_rejected.1.json index 52ab9969..5532e719 100644 --- a/contracts/token-factory/test_snapshots/test/test_mint_tokens_zero_amount_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_mint_tokens_zero_amount_rejected.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_non_admin_cannot_pause.1.json b/contracts/token-factory/test_snapshots/test/test_non_admin_cannot_pause.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_non_admin_cannot_pause.1.json +++ b/contracts/token-factory/test_snapshots/test/test_non_admin_cannot_pause.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_propose_admin_records_pending_state.1.json b/contracts/token-factory/test_snapshots/test/test_propose_admin_records_pending_state.1.json new file mode 100644 index 00000000..88127139 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_propose_admin_records_pending_state.1.json @@ -0,0 +1,446 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": { + "u64": "17280" + } + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_propose_admin_self_transfer_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_propose_admin_self_transfer_rejected.1.json new file mode 100644 index 00000000..2268ab7f --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_propose_admin_self_transfer_rejected.1.json @@ -0,0 +1,400 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_propose_admin_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_propose_admin_unauthorized.1.json new file mode 100644 index 00000000..14a8fb0c --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_propose_admin_unauthorized.1.json @@ -0,0 +1,400 @@ +{ + "generators": { + "address": 6, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_reentrancy_lock_released_after_error.1.json b/contracts/token-factory/test_snapshots/test/test_reentrancy_lock_released_after_error.1.json index 9239610f..85f386b6 100644 --- a/contracts/token-factory/test_snapshots/test/test_reentrancy_lock_released_after_error.1.json +++ b/contracts/token-factory/test_snapshots/test/test_reentrancy_lock_released_after_error.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_succeeds_and_clears.1.json b/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_succeeds_and_clears.1.json index 46cb5a80..84d60065 100644 --- a/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_succeeds_and_clears.1.json +++ b/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_succeeds_and_clears.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_unauthorized.1.json index 879e51a4..14a8fb0c 100644 --- a/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_remove_from_whitelist_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_second_proposal_overwrites_first.1.json b/contracts/token-factory/test_snapshots/test/test_second_proposal_overwrites_first.1.json new file mode 100644 index 00000000..597b9857 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_second_proposal_overwrites_first.1.json @@ -0,0 +1,525 @@ +{ + "generators": { + "address": 6, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "propose_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", + "key": { + "ledger_key_nonce": { + "nonce": "4270020994084947596" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_disables_then_reenables.1.json b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_disables_then_reenables.1.json index 58ae3e81..bd55c227 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_disables_then_reenables.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_disables_then_reenables.1.json @@ -554,7 +554,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -615,12 +615,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_lock_released_after_success.1.json b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_lock_released_after_success.1.json index 4fefff36..bd16bedd 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_lock_released_after_success.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_lock_released_after_success.1.json @@ -463,7 +463,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -524,12 +524,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_reentrancy_guard.1.json b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_reentrancy_guard.1.json index 59d7b116..d2ed9fb4 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_reentrancy_guard.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_reentrancy_guard.1.json @@ -439,7 +439,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -500,12 +500,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unauthorized.1.json index e19c4314..800477e3 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unauthorized.1.json @@ -438,7 +438,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -499,12 +499,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unregistered_token_fails.1.json b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unregistered_token_fails.1.json index 101a980a..ba9a9cc9 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unregistered_token_fails.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_burn_enabled_unregistered_token_fails.1.json @@ -213,7 +213,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -274,12 +274,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_at_max_recipients_accepted.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_at_max_recipients_accepted.1.json index 5e1b0939..f3f93645 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_at_max_recipients_accepted.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_at_max_recipients_accepted.1.json @@ -364,7 +364,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -425,12 +425,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_empty_clears_split.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_empty_clears_split.1.json index 3710d228..cd099359 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_empty_clears_split.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_empty_clears_split.1.json @@ -253,7 +253,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -314,12 +314,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_exactly_at_cap_accepted.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_exactly_at_cap_accepted.1.json index 15dc6b64..93007af7 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_exactly_at_cap_accepted.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_exactly_at_cap_accepted.1.json @@ -364,7 +364,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -425,12 +425,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_invalid_sum_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_invalid_sum_rejected.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_invalid_sum_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_invalid_sum_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_over_max_recipients_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_over_max_recipients_rejected.1.json index d24ef771..d319f004 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_over_max_recipients_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_over_max_recipients_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_too_many_recipients_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_too_many_recipients_rejected.1.json index d24ef771..d319f004 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_too_many_recipients_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_too_many_recipients_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_unauthorized.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_valid.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_valid.1.json index 3bdc587d..cad5aacd 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_valid.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_valid.1.json @@ -236,7 +236,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -297,12 +297,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_fee_split_zero_bps_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_set_fee_split_zero_bps_rejected.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_fee_split_zero_bps_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_fee_split_zero_bps_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata.1.json index 823155af..693d2516 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata.1.json @@ -583,7 +583,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -644,12 +644,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_already_set.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_already_set.1.json index 3eef882b..591ffaa4 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_already_set.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_already_set.1.json @@ -779,7 +779,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -840,12 +840,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_different_tokens_independent.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_different_tokens_independent.1.json index eef9a6c9..56ab3766 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_different_tokens_independent.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_different_tokens_independent.1.json @@ -913,7 +913,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -974,12 +974,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_fee_goes_to_treasury.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_fee_goes_to_treasury.1.json index 823155af..693d2516 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_fee_goes_to_treasury.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_fee_goes_to_treasury.1.json @@ -583,7 +583,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -644,12 +644,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_insufficient_fee.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_insufficient_fee.1.json index 101a980a..ba9a9cc9 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_insufficient_fee.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_insufficient_fee.1.json @@ -213,7 +213,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -274,12 +274,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_lock_released_after_success.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_lock_released_after_success.1.json index e8affa9f..742bd793 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_lock_released_after_success.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_lock_released_after_success.1.json @@ -583,7 +583,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -644,12 +644,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_overpayment_charges_exact_fee_only.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_overpayment_charges_exact_fee_only.1.json index 7fbd6a11..970688b2 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_overpayment_charges_exact_fee_only.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_overpayment_charges_exact_fee_only.1.json @@ -584,7 +584,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -645,12 +645,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_reentrancy_guard.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_reentrancy_guard.1.json index b87ce810..2d841251 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_reentrancy_guard.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_reentrancy_guard.1.json @@ -481,7 +481,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -542,12 +542,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_empty_uri.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_empty_uri.1.json index 6d9ed580..c107d48f 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_empty_uri.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_empty_uri.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_missing_ipfs_prefix.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_missing_ipfs_prefix.1.json index 6d9ed580..c107d48f 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_missing_ipfs_prefix.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_missing_ipfs_prefix.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_prefix_only.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_prefix_only.1.json index 6d9ed580..c107d48f 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_prefix_only.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_prefix_only.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_uri_too_long.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_uri_too_long.1.json index 6d9ed580..c107d48f 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_uri_too_long.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_rejects_uri_too_long.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_unauthorized.1.json index 13da5c6a..bca8824e 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_unauthorized.1.json @@ -480,7 +480,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -541,12 +541,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_unregistered_token_fails.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_unregistered_token_fails.1.json index 05397772..2fc09187 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_unregistered_token_fails.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_unregistered_token_fails.1.json @@ -255,7 +255,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -316,12 +316,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_update_then_freeze.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_update_then_freeze.1.json index 772400ab..16705735 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_update_then_freeze.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_update_then_freeze.1.json @@ -685,7 +685,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -746,12 +746,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_metadata_version_increments.1.json b/contracts/token-factory/test_snapshots/test/test_set_metadata_version_increments.1.json index b280f9b2..dcd061c3 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_metadata_version_increments.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_metadata_version_increments.1.json @@ -683,7 +683,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -744,12 +744,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_succeeds_and_updates_state.1.json b/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_succeeds_and_updates_state.1.json index 35aebd42..18274a96 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_succeeds_and_updates_state.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_succeeds_and_updates_state.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -255,12 +255,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_toggles_flag.1.json b/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_toggles_flag.1.json index 902d3e6d..98491f35 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_toggles_flag.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_toggles_flag.1.json @@ -237,7 +237,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -298,12 +298,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_unauthorized.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_set_whitelist_enabled_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.1.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.1.json index 3fd5565b..31f817b2 100644 --- a/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.1.json +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.1.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -212,7 +212,7 @@ "symbol": "admin" }, "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" } }, { @@ -255,12 +255,28 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": { + "u64": "17280" + } + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.2.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.2.json index 1d2b3953..0fb89009 100644 --- a/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.2.json +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_produce_same_state.2.json @@ -194,7 +194,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -212,7 +212,7 @@ "symbol": "admin" }, "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" } }, { @@ -255,12 +255,28 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": { + "u64": "17280" + } + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_share_guards.1.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_share_guards.1.json index da3a8ba9..70fff4ae 100644 --- a/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_share_guards.1.json +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_and_update_admin_share_guards.1.json @@ -155,7 +155,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -216,12 +216,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_delegates_to_propose_admin.1.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_delegates_to_propose_admin.1.json new file mode 100644 index 00000000..e0cad748 --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_delegates_to_propose_admin.1.json @@ -0,0 +1,483 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "transfer_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_grants_new_admin_rights.1.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_grants_new_admin_rights.1.json index 4748effd..e5320beb 100644 --- a/contracts/token-factory/test_snapshots/test/test_transfer_admin_grants_new_admin_rights.1.json +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_grants_new_admin_rights.1.json @@ -82,6 +82,28 @@ ] ], [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -215,7 +237,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -276,12 +298,24 @@ "bool": true } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -328,6 +362,26 @@ }, "live_until": 535000 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_same_address_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_same_address_rejected.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_transfer_admin_same_address_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_same_address_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_transfer_admin_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_transfer_admin_unauthorized.1.json index 879e51a4..14a8fb0c 100644 --- a/contracts/token-factory/test_snapshots/test/test_transfer_admin_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_transfer_admin_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_ttl_extended_after_initialize.1.json b/contracts/token-factory/test_snapshots/test/test_ttl_extended_after_initialize.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_ttl_extended_after_initialize.1.json +++ b/contracts/token-factory/test_snapshots/test/test_ttl_extended_after_initialize.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_admin_delegates_to_propose_admin.1.json b/contracts/token-factory/test_snapshots/test/test_update_admin_delegates_to_propose_admin.1.json new file mode 100644 index 00000000..319f5e3b --- /dev/null +++ b/contracts/token-factory/test_snapshots/test/test_update_admin_delegates_to_propose_admin.1.json @@ -0,0 +1,483 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "__constructor", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "i128": "1000" + }, + { + "i128": "500" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "update_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 27, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + "live_until": null + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "sv" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "vec": [ + { + "symbol": "State" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "admin" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + }, + { + "key": { + "symbol": "base_fee" + }, + "val": { + "i128": "1000" + } + }, + { + "key": { + "symbol": "fee_token" + }, + "val": { + "address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF" + } + }, + { + "key": { + "symbol": "locked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "metadata_fee" + }, + "val": { + "i128": "500" + } + }, + { + "key": { + "symbol": "paused" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, + { + "key": { + "symbol": "schema_version" + }, + "val": { + "u32": 4 + } + }, + { + "key": { + "symbol": "token_count" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "token_wasm_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "treasury" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "whitelist_enabled" + }, + "val": { + "bool": false + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 535000 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 120960 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 535000 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token-factory/test_snapshots/test/test_update_admin_old_loses_access.1.json b/contracts/token-factory/test_snapshots/test/test_update_admin_old_loses_access.1.json index c04dea9c..ec9bb37e 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_admin_old_loses_access.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_admin_old_loses_access.1.json @@ -82,6 +82,26 @@ ] ], [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -214,7 +234,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -275,12 +295,24 @@ "bool": true } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -336,7 +368,27 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", "key": { "ledger_key_nonce": { - "nonce": "2032731177588607455" + "nonce": "4270020994084947596" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" } }, "durability": "temporary", diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees.1.json index 1b1a816c..f455e94d 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees.1.json @@ -197,7 +197,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -258,12 +258,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_i128_min_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_i128_min_rejected.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_i128_min_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_i128_min_rejected.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_negative_base_fee_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_negative_base_fee_rejected.1.json index 8fdd471f..4cf9b07d 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_negative_base_fee_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_negative_base_fee_rejected.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_negative_does_not_corrupt_state.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_negative_does_not_corrupt_state.1.json index 8fdd471f..4cf9b07d 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_negative_does_not_corrupt_state.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_negative_does_not_corrupt_state.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_negative_metadata_fee_rejected.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_negative_metadata_fee_rejected.1.json index 8fdd471f..4cf9b07d 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_negative_metadata_fee_rejected.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_negative_metadata_fee_rejected.1.json @@ -153,7 +153,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -214,12 +214,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_partial.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_partial.1.json index 6737e345..5f42a2b9 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_partial.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_partial.1.json @@ -195,7 +195,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -256,12 +256,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_unauthorized.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_update_fees_zero_allowed.1.json b/contracts/token-factory/test_snapshots/test/test_update_fees_zero_allowed.1.json index b4da30c1..ec6e2b61 100644 --- a/contracts/token-factory/test_snapshots/test/test_update_fees_zero_allowed.1.json +++ b/contracts/token-factory/test_snapshots/test/test_update_fees_zero_allowed.1.json @@ -197,7 +197,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -258,12 +258,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_upgrade_unauthorized.1.json b/contracts/token-factory/test_snapshots/test/test_upgrade_unauthorized.1.json index 19a651ac..da796622 100644 --- a/contracts/token-factory/test_snapshots/test/test_upgrade_unauthorized.1.json +++ b/contracts/token-factory/test_snapshots/test/test_upgrade_unauthorized.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_whitelist_add_remove_create_sequence.1.json b/contracts/token-factory/test_snapshots/test/test_whitelist_add_remove_create_sequence.1.json index a1e7fff9..689c41a4 100644 --- a/contracts/token-factory/test_snapshots/test/test_whitelist_add_remove_create_sequence.1.json +++ b/contracts/token-factory/test_snapshots/test/test_whitelist_add_remove_create_sequence.1.json @@ -280,7 +280,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -341,12 +341,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_whitelist_disable_reopens_factory.1.json b/contracts/token-factory/test_snapshots/test/test_whitelist_disable_reopens_factory.1.json index 50ba636f..c04f236b 100644 --- a/contracts/token-factory/test_snapshots/test/test_whitelist_disable_reopens_factory.1.json +++ b/contracts/token-factory/test_snapshots/test/test_whitelist_disable_reopens_factory.1.json @@ -279,7 +279,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -340,12 +340,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_whitelist_disabled_by_default.1.json b/contracts/token-factory/test_snapshots/test/test_whitelist_disabled_by_default.1.json index 26b08f97..2268ab7f 100644 --- a/contracts/token-factory/test_snapshots/test/test_whitelist_disabled_by_default.1.json +++ b/contracts/token-factory/test_snapshots/test/test_whitelist_disabled_by_default.1.json @@ -152,7 +152,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -213,12 +213,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_whitelist_gate_consistent_across_single_and_batch.1.json b/contracts/token-factory/test_snapshots/test/test_whitelist_gate_consistent_across_single_and_batch.1.json index c4d50972..14a44ab8 100644 --- a/contracts/token-factory/test_snapshots/test/test_whitelist_gate_consistent_across_single_and_batch.1.json +++ b/contracts/token-factory/test_snapshots/test/test_whitelist_gate_consistent_across_single_and_batch.1.json @@ -306,7 +306,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -367,12 +367,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_legacy_instance_entry.1.json b/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_legacy_instance_entry.1.json index af1ab1dd..78074092 100644 --- a/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_legacy_instance_entry.1.json +++ b/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_legacy_instance_entry.1.json @@ -238,7 +238,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -299,12 +299,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_persistent_entry.1.json b/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_persistent_entry.1.json index 12975201..1e29b088 100644 --- a/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_persistent_entry.1.json +++ b/contracts/token-factory/test_snapshots/test/test_whitelist_gate_honors_persistent_entry.1.json @@ -264,7 +264,7 @@ "symbol": "sv" }, "val": { - "u32": 3 + "u32": 4 } }, { @@ -325,12 +325,24 @@ "bool": false } }, + { + "key": { + "symbol": "pending_admin" + }, + "val": "void" + }, + { + "key": { + "symbol": "pending_admin_expiry" + }, + "val": "void" + }, { "key": { "symbol": "schema_version" }, "val": { - "u32": 3 + "u32": 4 } }, { diff --git a/docs/CODEBASE_AUDIT_CHECKLIST.md b/docs/CODEBASE_AUDIT_CHECKLIST.md index b3a40664..e675cec2 100644 --- a/docs/CODEBASE_AUDIT_CHECKLIST.md +++ b/docs/CODEBASE_AUDIT_CHECKLIST.md @@ -1,6 +1,6 @@ # Stellar Forge Codebase Audit - Issue Checklist -This document tracks progress on the comprehensive codebase audit mentioned in the task description (20 issues identified). +This document tracks progress on the comprehensive codebase audit mentioned in the task description (20 issues identified). **Last Updated**: 2024 @@ -18,12 +18,14 @@ The audit identified 20 distinct issues across the frontend service layer, contr **Severity**: CRITICAL **Component**: frontend/src/services/stellar-impl.ts (deployToken method) -**Problem**: +**Problem**: + - Contract expects 7 arguments: `(creator, salt, name, symbol, decimals, initial_supply, fee_payment)` - Frontend was passing 8 arguments, inserting `tokenWasmHash` between salt and name - Result: Every token deployment transaction failed at RPC simulation **Fix Applied**: + 1. ✅ Removed `tokenWasmHash` from `TokenDeployParams` interface 2. ✅ Removed erroneous argument from `contract.call('create_token', ...)` 3. ✅ Updated all callers (CreateToken.tsx, stellar.ts wrapper) @@ -33,6 +35,7 @@ The audit identified 20 distinct issues across the frontend service layer, contr 7. ✅ Created comprehensive audit document (docs/STELLAR_IMPL_ABI_AUDIT.md) **Files Modified**: + - `frontend/src/types/index.ts` - Removed tokenWasmHash from TokenDeployParams - `frontend/src/services/stellar-impl.ts` - Fixed deployToken contract.call - `frontend/src/services/stellar.ts` - Updated wrapper signature @@ -43,6 +46,7 @@ The audit identified 20 distinct issues across the frontend service layer, contr - `docs/ISSUE_5_FIX_SUMMARY.md` - **NEW** - Detailed fix summary **Verification**: + - ✅ TypeScript compiler: No diagnostics on affected files - ✅ Type safety: tokenWasmHash parameter rejected at compile-time - ✅ Contract signature audit: All 5 contract.call sites verified correct @@ -54,16 +58,16 @@ The audit identified 20 distinct issues across the frontend service layer, contr The following issues remain in the codebase and should be tracked in a dedicated ISSUES.md: -| # | Title | Component | Severity | Status | -|---|-------|-----------|----------|--------| -| 1 | TBD | - | - | Not started | -| 2 | TBD | - | - | Not started | -| 3 | TBD | - | - | Not started | -| 4 | TBD | - | - | Not started | -| 5 | create_token contract call mismatch | stellar-impl.ts | CRITICAL | ✅ FIXED | -| 6 | TBD | - | - | Not started | -| ... | ... | ... | ... | ... | -| 20 | TBD | - | - | Not started | +| # | Title | Component | Severity | Status | +| --- | ----------------------------------- | --------------- | -------- | ----------- | +| 1 | TBD | - | - | Not started | +| 2 | TBD | - | - | Not started | +| 3 | TBD | - | - | Not started | +| 4 | TBD | - | - | Not started | +| 5 | create_token contract call mismatch | stellar-impl.ts | CRITICAL | ✅ FIXED | +| 6 | TBD | - | - | Not started | +| ... | ... | ... | ... | ... | +| 20 | TBD | - | - | Not started | --- @@ -95,7 +99,7 @@ For each issue in the codebase audit, the following checklist should be applied: - Verifies error variants in lib.rs are documented in contract-abi.md - **NEW**: Scans stellar-impl.ts for contract.call invocations -2. ❌ *Missing*: Parameter signature validation +2. ❌ _Missing_: Parameter signature validation - Currently: Can't validate argument count/types match - Recommendation: Create automated parser comparing Rust function signatures to TypeScript contract.call invocations diff --git a/docs/STELLAR_IMPL_ABI_AUDIT.md b/docs/STELLAR_IMPL_ABI_AUDIT.md index 1511a34b..0e81cf28 100644 --- a/docs/STELLAR_IMPL_ABI_AUDIT.md +++ b/docs/STELLAR_IMPL_ABI_AUDIT.md @@ -21,6 +21,7 @@ TypeScript never caught this because `contract.call(...)` accepts a variadic `.. ### Why It Happened Every write path independently hand-builds its argument list: + - `deployToken` - `mintTokens` - `burnTokens` @@ -77,6 +78,7 @@ All existing call sites pass with zero modifications required: ## Integration into CI The check runs in the `drift-checks` job in `.github/workflows/ci.yml`, alongside: + - `check-abi-doc-drift.sh` (verifies ABI documentation) - `check-event-topic-drift.sh` (verifies event topics) - `check-validation-drift.sh` (verifies validation bounds) @@ -125,10 +127,12 @@ CI will fail and prevent the broken code from being merged. ## Limitations & Future Enhancements ### Current Scope + - Counts arguments only; does not validate argument types or order within the argument list - Regex-based parsing; does not use a full TypeScript AST parser ### Potential Improvements (M6+) + 1. **Type validation**: Compare argument types (e.g., `Address` vs `u32`) against Rust parameter types 2. **Order validation**: Ensure arguments are reordered intentionally, not accidentally 3. **Rust-to-TypeScript codegen**: Generate a typed argument builder from `lib.rs` signatures (removes manual argument construction entirely) @@ -140,13 +144,14 @@ The unchecked item at `docs/CODEBASE_AUDIT_CHECKLIST.md:102-104` is now marked d ```markdown - [x] Add AST-based parameter validation comparing stellar-impl.ts to contract signatures - Implementation: scripts/check-stellar-impl-abi.mjs (integrated into CI) - Reference: docs/STELLAR_IMPL_ABI_AUDIT.md + Implementation: scripts/check-stellar-impl-abi.mjs (integrated into CI) + Reference: docs/STELLAR_IMPL_ABI_AUDIT.md ``` This mechanism replaces the manual-audit approach used to resolve issue #5 with an automated, continuous check that runs on every CI job, ensuring the gap cannot silently regress. ## See Also + - **Issue #5**: CRITICAL token deployment failures (RESOLVED) - **Issue #946**: Contract interface drift detection (RESOLVED) - **docs/CODEBASE_AUDIT_CHECKLIST.md**: Full audit context diff --git a/docs/adr/ADR-005-analytics-privacy-consent.md b/docs/adr/ADR-005-analytics-privacy-consent.md index 5b2ba6a3..51a62f45 100644 --- a/docs/adr/ADR-005-analytics-privacy-consent.md +++ b/docs/adr/ADR-005-analytics-privacy-consent.md @@ -10,18 +10,18 @@ StellarForge includes a lightweight analytics integration using [Plausible](https://plausible.io) — a privacy-first, cookieless analytics -provider. Plausible collects no PII, sets no cookies, and is GDPR-compliant +provider. Plausible collects no PII, sets no cookies, and is GDPR-compliant by design. Nonetheless, the app includes an explicit opt-out mechanism (`AnalyticsOptOut.tsx`) because: 1. **GDPR (EU)** — Art. 6(1)(f) legitimate interest only applies where the - user's interests do not override the controller's. Providing an easy + user's interests do not override the controller's. Providing an easy opt-out is a common mitigation and aligns with the spirit of data minimisation. 2. **CCPA (California)** — Users have the right to opt out of the "sale" or - "sharing" of personal information. Even though Plausible collects + "sharing" of personal information. Even though Plausible collects aggregate data that is not personal information, offering an opt-out satisfies the broadest reasonable reading of the CCPA requirement. 3. **User trust** — Explicit opt-out UI signals transparency and builds trust @@ -38,14 +38,14 @@ Plausible was chosen for analytics because: - No cookies, no cross-site tracking, no fingerprinting. - Aggregated statistics only — no individual user profiles. - Self-hostable; the `VITE_PLAUSIBLE_DOMAIN` env var gates the entire - analytics subsystem. If the var is unset (e.g., in development, tests, + analytics subsystem. If the var is unset (e.g., in development, tests, or a self-hosted deployment that opts out entirely), **zero** analytics calls are made. ### Opt-out mechanism The opt-out preference is stored in `localStorage` under the key -`analytics_opt_out`. The analytics service (`src/services/analytics.ts`) +`analytics_opt_out`. The analytics service (`src/services/analytics.ts`) reads this key on **every** tracking call via `isOptedOut()`: ``` @@ -53,7 +53,7 @@ isEnabled() → !isOptedOut() && VITE_PLAUSIBLE_DOMAIN configured ``` This means opt-out takes effect **immediately in the current session** — -no page reload is required. A user who toggles the opt-out checkbox +no page reload is required. A user who toggles the opt-out checkbox mid-session will have all subsequent analytics calls suppressed within the same page load. @@ -61,10 +61,10 @@ the same page load. Only two categories of events are tracked: -| Event | Call site | Contains PII? | -|-------|-----------|---------------| -| `pageview` | `App.tsx` `useEffect` on route change | No — path only (e.g. `/create`) | -| Custom events (`token_created`, `mint_tokens`, etc.) | `trackEvent()` callers | No — event name + optional non-PII props | +| Event | Call site | Contains PII? | +| ---------------------------------------------------- | ------------------------------------- | ---------------------------------------- | +| `pageview` | `App.tsx` `useEffect` on route change | No — path only (e.g. `/create`) | +| Custom events (`token_created`, `mint_tokens`, etc.) | `trackEvent()` callers | No — event name + optional non-PII props | **Wallet addresses are never included in analytics events.** This is enforced by code review and by the `trackEvent` type signature which @@ -75,23 +75,23 @@ could accidentally include addresses). ## Regulatory compliance analysis -| Requirement | Satisfied? | How | -|-------------|-----------|-----| -| No PII collected | ✅ | Plausible design + prop type constraint | -| No cookies | ✅ | Plausible is cookieless by default | -| Opt-out available | ✅ | `AnalyticsOptOut` component in app footer | -| Opt-out persisted | ✅ | `localStorage` (survives reload) | -| Opt-out takes effect immediately | ✅ | `isOptedOut()` read on every call | -| Opt-out backed by tests | ✅ | `analytics.test.ts`, `useAnalytics.test.ts`, `AnalyticsOptOut.test.tsx` | -| New bypass call sites detected | ✅ | `scripts/check-analytics-bypass.mjs` (CI-enforced) | -| Analytics disabled when unconfigured | ✅ | `VITE_PLAUSIBLE_DOMAIN` guard | +| Requirement | Satisfied? | How | +| ------------------------------------ | ---------- | ----------------------------------------------------------------------- | +| No PII collected | ✅ | Plausible design + prop type constraint | +| No cookies | ✅ | Plausible is cookieless by default | +| Opt-out available | ✅ | `AnalyticsOptOut` component in app footer | +| Opt-out persisted | ✅ | `localStorage` (survives reload) | +| Opt-out takes effect immediately | ✅ | `isOptedOut()` read on every call | +| Opt-out backed by tests | ✅ | `analytics.test.ts`, `useAnalytics.test.ts`, `AnalyticsOptOut.test.tsx` | +| New bypass call sites detected | ✅ | `scripts/check-analytics-bypass.mjs` (CI-enforced) | +| Analytics disabled when unconfigured | ✅ | `VITE_PLAUSIBLE_DOMAIN` guard | --- ## Consequences - Any new tracking call site **must** go through `trackEvent()` or - `trackPageView()` from `src/services/analytics.ts`. Direct use of + `trackPageView()` from `src/services/analytics.ts`. Direct use of `window.plausible` bypasses the consent check and is blocked by the CI lint rule (`npm run check:analytics-bypass`). - To add a new allowed caller that imports from `services/analytics` @@ -107,16 +107,16 @@ ADR-005 is enforced at runtime, statically, and through automated tests. The traceability IDs below are the canonical links between this decision and its evidence: -| Requirement | Runtime/test evidence | Static or QA enforcement | -|---|---|---| -| `REQ-ADR005-01` No PII or wallet addresses | `analytics.test.ts` verifies scalar props and documented payload shape | Caller inventory and payload review; no complex objects are permitted | -| `REQ-ADR005-02` No cookies, fingerprinting, or cross-site tracking | Provider property, not fully unit-testable | Network/storage audit required in QA | -| `REQ-ADR005-03` Opt-out is available when configured | `AnalyticsOptOut.test.tsx` verifies rendering and accessible control | Configuration guard | -| `REQ-ADR005-04` Preference persistence | `analytics.test.ts` and `AnalyticsOptOut.test.tsx` verify `analytics_opt_out` | Browser reload verification in QA | -| `REQ-ADR005-05` Immediate suppression and reactivation | Both suites verify in-session transitions without reload | `isOptedOut()` is evaluated on every tracking call | -| `REQ-ADR005-06` Pageview/custom event payload contract | `analytics.test.ts` verifies pageview URL and scalar props | Payload and caller inventory review | -| `REQ-ADR005-07` Disabled when domain is absent | Service and component tests verify zero calls/hidden control | `VITE_PLAUSIBLE_DOMAIN` configuration review | -| `REQ-ADR005-08` Zero direct bypasses | Service tests verify public API behavior | `frontend/scripts/check-analytics-bypass.mjs` blocks direct imports and `window.plausible` calls | +| Requirement | Runtime/test evidence | Static or QA enforcement | +| ------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `REQ-ADR005-01` No PII or wallet addresses | `analytics.test.ts` verifies scalar props and documented payload shape | Caller inventory and payload review; no complex objects are permitted | +| `REQ-ADR005-02` No cookies, fingerprinting, or cross-site tracking | Provider property, not fully unit-testable | Network/storage audit required in QA | +| `REQ-ADR005-03` Opt-out is available when configured | `AnalyticsOptOut.test.tsx` verifies rendering and accessible control | Configuration guard | +| `REQ-ADR005-04` Preference persistence | `analytics.test.ts` and `AnalyticsOptOut.test.tsx` verify `analytics_opt_out` | Browser reload verification in QA | +| `REQ-ADR005-05` Immediate suppression and reactivation | Both suites verify in-session transitions without reload | `isOptedOut()` is evaluated on every tracking call | +| `REQ-ADR005-06` Pageview/custom event payload contract | `analytics.test.ts` verifies pageview URL and scalar props | Payload and caller inventory review | +| `REQ-ADR005-07` Disabled when domain is absent | Service and component tests verify zero calls/hidden control | `VITE_PLAUSIBLE_DOMAIN` configuration review | +| `REQ-ADR005-08` Zero direct bypasses | Service tests verify public API behavior | `frontend/scripts/check-analytics-bypass.mjs` blocks direct imports and `window.plausible` calls | ### Runtime enforcement diff --git a/docs/context/fix-ci-monorepo-pipeline-context.md b/docs/context/fix-ci-monorepo-pipeline-context.md index 73402241..e50d27f0 100644 --- a/docs/context/fix-ci-monorepo-pipeline-context.md +++ b/docs/context/fix-ci-monorepo-pipeline-context.md @@ -1,4 +1,5 @@ # Contexto de Ejecución: Fix CI Monorepo & Access Control Drift + - **Estado:** Fase 4 (Cierre y PR listo) - **Rama:** fix/ci-monorepo-drift-and-builds - **Fecha:** 2026-08-24 18:15:00 UTC @@ -17,21 +18,25 @@ ## 1) Diagnóstico Arquitectónico de los 5 checks y el workflow ### 1.1. Rust Formatting (`cargo fmt --check`) + - **Causa raíz técnica:** el check depende del toolchain de Rust y de `rustfmt` en el workspace `contracts/`. La validación exige que el código fuente del contrato esté formateado en el mismo estilo que el formatter oficial; cualquier cambio de formato o estilo de código produce un fallo determinista. - **Contrato / interfaz afectada:** `contracts/token-factory/src/lib.rs` y el resto del workspace Rust de `contracts/`. - **Estrategia de corrección:** aplicar `cargo fmt` en el workspace Rust y mantener el mismo toolchain en CI (`dtolnay/rust-toolchain@stable` con `components: rustfmt`). La regla arquitectónica es que la fuente del contrato es el SSoT; el formatter no debe ser un check opcional. ### 1.2. Contract Build (`cargo build --target wasm32v1-none --release`) + - **Causa raíz técnica:** el build del contrato está acoplado a un target WASM específico, con una cadena de compilation y toolchain que debe ser consistente entre local, Docker y CI. El monorepo ya muestra versión/target drift entre `wasm32v1-none`, `wasm32-unknown-unknown` y los docs/scripts asociados. - **Contrato / interfaz afectada:** `contracts/token-factory`, artefactos WASM, bindings y hashes emitidos desde `token_wasm_hash`. - **Estrategia de corrección:** estandarizar el target de compilación en una única fuente de verdad para CI y scripts; documentar la versión del target y el hash del WASM para evitar drift entre compilación del contrato y verificación del frontend. ### 1.3. Contract Tests (`cargo test`) + - **Causa raíz técnica:** las pruebas del contrato dependen de la misma fuente de verdad del ABI y los eventos; cualquier cambio en los `symbol_short!`, `contracterror`, la firma de entradas o los permisos altera las expectativas de las pruebas y rompe la validación end-to-end. - **Contrato / interfaz afectada:** `contracts/token-factory/src/lib.rs`, `tests` del contract y cualquier fixture de eventos/validación asociada. - **Estrategia de corrección:** asegurar que la firma del contrato, los eventos públicos, los errores y la lógica de acceso se validen juntos antes de cambios de código; aislar los contratos de frontend y no asumir que los tests del UI cubren el comportamiento on-chain. ### 1.4. Contract/Frontend Drift + - **Causa raíz técnica:** la misma semántica del contrato se replica en varios artefactos: `docs/contract-abi.md`, `frontend/src/types/index.ts`, `frontend/src/services/stellar-impl.ts`, `scripts/check-*drift*.sh`, y `scripts/check-stellar-impl-abi.mjs`. Si se modifica el contrato pero no se actualiza el frontend o la documentación, el check de drift detecta divergencia. - **Contrato / interfaz afectada:** - `lib.rs` ← función pública / `symbol_short!` / `contracterror` / validación @@ -41,28 +46,31 @@ - **Estrategia de corrección:** una regla simple: `lib.rs` es la fuente de verdad; la documentación, bindings, tipos y validación del frontend deben ser regenerados o validados desde esa fuente. El CI debe bloquear PRs cuando la sincronización se rompe. ### 1.5. Frontend (`Typecheck`, `Lint`, `Tests`, `Build`) + - **Causa raíz técnica:** el frontend consume los tipos y la ABI del contrato de forma manual y, cuando fallan los checks de drift, los tests del UI y la capa de servicio dejan de reflejar el comportamiento real del contract. Casos típicos: nombres de eventos desalineados (`adm_upd` vs `admin_update`), validación de parámetros desincronizada y mocks heredados. - **Contrato / interfaz afectada:** `frontend/src/services/`, `frontend/src/types/`, `frontend/src/utils/`, y suites de pruebas como `TokenDetail.test.tsx`, `ipfs.test.ts`, `stellar-impl.test.ts`. - **Estrategia de corrección:** rechazar cambios de contrato sin actualización de los contratos y tests del frontend; mantener las comprobaciones de ABI, eventos y validación dentro de CI. ### 1.6. Workflow `.github/workflows/validate-access-control-drift.yml` (`No jobs were run`) + - **Causa raíz técnica:** el workflow está configurado con filtros `paths` que excluyen el propio workflow en los eventos de `push`, y el job sólo puede ejecutarse cuando se tocan `contracts/token-factory/src/lib.rs`, `docs/contract-abi.md`, `SECURITY.md` o el propio workflow en `pull_request`. Cuando el evento no coincide con ninguna ruta, GitHub reporta que el workflow no disparó jobs. - **Contrato / interfaz afectada:** pipeline de validación documental y seguridad del contrato. - **Estrategia de corrección:** añadir `workflow_dispatch` y/o triggers más explícitos, y asegurar que el workflow reacciona tanto a cambios del contrato como a cambios de la documentación y del propio YAML. Este paso no es un bug funcional del script, sino de la política de disparo del pipeline. ## 2) Matriz de sincronización de fuentes de verdad -| Dominio | Fuente de verdad | Dependencias que deben sincronizarse | Control de drift | -| --- | --- | --- | --- | -| Contract logic | `contracts/token-factory/src/lib.rs` | ABI docs, validation rules, event topics, admin/whitelist semantics | `scripts/check-abi-doc-drift.sh`, `scripts/check-event-topic-drift.sh`, `scripts/check-validation-drift.sh`, `scripts/check-access-control-docs-drift.sh` | -| Documentación pública | `docs/contract-abi.md` | Contrato + seguridad + UI | CI drift checks | -| Frontend state/types | `frontend/src/types/index.ts` | `stellar-impl.ts`, tests, DTOs | Typecheck + drift scripts | -| RPC/ABI integration | `frontend/src/services/stellar-impl.ts` | `lib.rs` signatures | `scripts/check-stellar-impl-abi.mjs` | -| GitHub Actions policy | `.github/workflows/*.yml` | Triggers, job guards, selective path filters | workflow validation + review | +| Dominio | Fuente de verdad | Dependencias que deben sincronizarse | Control de drift | +| --------------------- | --------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Contract logic | `contracts/token-factory/src/lib.rs` | ABI docs, validation rules, event topics, admin/whitelist semantics | `scripts/check-abi-doc-drift.sh`, `scripts/check-event-topic-drift.sh`, `scripts/check-validation-drift.sh`, `scripts/check-access-control-docs-drift.sh` | +| Documentación pública | `docs/contract-abi.md` | Contrato + seguridad + UI | CI drift checks | +| Frontend state/types | `frontend/src/types/index.ts` | `stellar-impl.ts`, tests, DTOs | Typecheck + drift scripts | +| RPC/ABI integration | `frontend/src/services/stellar-impl.ts` | `lib.rs` signatures | `scripts/check-stellar-impl-abi.mjs` | +| GitHub Actions policy | `.github/workflows/*.yml` | Triggers, job guards, selective path filters | workflow validation + review | ## 3) ADRs propuestos ### ADR-010: Single Source of Truth for Contract-to-Frontend Drift + - **Contexto:** El monorepo tenía varios artefactos duplicados de la misma lógica del contrato y el frontend hacía suposiciones manuales. Eso habilitó varios tipos de drift silencioso. - **Decisión:** `contracts/token-factory/src/lib.rs` será la única fuente autoritativa para nombres públicos, eventos, validaciones y permisos. La documentación y los tipos del frontend deben validarse contra ella en CI. - **Consecuencias:** @@ -72,6 +80,7 @@ - Requiere mantener scripts de drift y tipos alineados con el contrato ### ADR-011: CI Workflow Trigger Policy for Security and Contract Validation + - **Contexto:** Los workflows de validación no siempre se disparaban porque los filtros de `paths` no cubrían todos los eventos relevantes. - **Decisión:** los workflows de contrato/seguridad deben dispararse en cambios del contrato, de la documentación y del propio workflow, y deben admitir `workflow_dispatch` para diagnósticos manuales. - **Consecuencias:** @@ -80,6 +89,7 @@ - Menos dependencia de la memoria del equipo ### ADR-012: Standardized Rust Toolchain & Formatting Gate + - **Contexto:** La validación de Rust fallaba porque el proyecto exige un toolchain consistente y `rustfmt` instalado; el monorepo tiene varios mapeos de target y toolchain que no están unificados. - **Decisión:** CI usará una toolchain estable y documentada, con `rustfmt` y el target de compilación específico para `token-factory`, y cualquier cambio que requiera un target diferente deberá documentarse como un cambio de arquitectura. - **Consecuencias:** @@ -90,12 +100,14 @@ ## 4) Especificación de sincronización de contrato y frontend ### 4.1. Contrato público del token-factory + - Los nombres públicos expuestos por `lib.rs` deben ser la base de las firmas usadas por `stellar-impl.ts` y las comprobaciones de drift. - Los `symbol_short!` de eventos deben corresponder exactamente con `ContractEventType` en `frontend/src/types/index.ts`. - Los códigos de error del contrato deben mantenerse consistentes con los mappings de `frontend/src/utils/contractErrors.ts`. - Las validaciones de entrada y límites deben coincidir con `scripts/check-validation-drift.sh` y `frontend/src/utils/validation.ts`. ### 4.2. Reglas de sincronización + 1. Ningún cambio en `contracts/token-factory/src/lib.rs` puede fusionarse sin actualizar la documentación pública (`docs/contract-abi.md`) y la validación de seguridad (`SECURITY.md`) si aplica. 2. Si un evento cambia de nombre o un error cambia de código, el frontend debe actualizar su mapping y sus tests. 3. Si cambia el `token_wasm_hash` del contrato o el target de compilación, la comprobación de WASM/hash debe actualizarse antes del merge. @@ -104,12 +116,14 @@ ## 5) Plan detallado por fases ### Fase 2: Contract & Frontend remediation + - Reconciliar `lib.rs` con documentación, validaciones y bindings del frontend. - Aplicar `cargo fmt` y normalizar toolchain/target. - Ajustar `stellar-impl.ts`, tipos de frontend y tests para que reflejen la ABI del contrato real. - Corregir los scripts de drift y asegurar que se ejecuten en CI de forma determinista. ### Fase 3: QA y validación final + - Ejecutar los checks de Rust, contract build/tests, frontend, drift y workflow en orden. - Verificar que el workflow `.github/workflows/validate-access-control-drift.yml` dispara en PR y push no filtrados. - Confirmar que no existen regresiones en el pipeline y que los checks de seguridad/documentación vuelven a ser verdes. @@ -117,46 +131,55 @@ ## 6) Reporte final de QA ejecutado ### 6.1. Verificación de TypeScript + - Ejecución: `cd frontend && npm run typecheck -- --pretty false` - Resultado: `PASS` - Evidencia: `tsc --noEmit -p tsconfig.json --pretty false` terminó sin errores de compilación ni fallos de tipado. ### 6.2. Verificación de suites frontend + - Ejecución: `cd frontend && npx vitest run` - Resultado: `PASS` - Métrica: `66` archivos de prueba pasados, `707` tests pasados, `0` fallidos. - Duración: `10.32s` total de suite en entorno Vitest; tiempo de ejecución del comando registrado en la sesión de QA del 2026-08-24. ### 6.3. Verificación de guard de drift de analytics / bypass + - Ejecución: `cd frontend && npm run check:analytics-bypass` - Resultado: `PASS` - Evidencia: `✅ Analytics bypass check passed — no violations found.` ### 6.4. Validación del workflow de GitHub Actions + - Archivo revisado: `.github/workflows/validate-access-control-drift.yml` - Resultado: `PASS` con triggers correctos para `pull_request`, `push` y `workflow_dispatch`. - Verificación: el `on:` del workflow incluye ramas `main`, filtros de `paths` relevantes para `contracts/**`, `docs/**`, `SECURITY.md`, `.github/workflows/**` y el script de validación, sin filtros excluyentes inválidos ni condiciones que impidan la ejecución en eventos relevantes. - Observación: la configuración es compatible con la política ADR-011 y evita el patrón “No jobs were run” al mantener disparadores explícitos y cobertura de cambios. ### 6.5. Veredicto formal de QA + - Veredicto: `[APROBADO]` - No-regresión: confirmada para la capa frontend y la validación CI revisada. - Estado final: la Fase 3 queda cerrada con la validación integral de QA completada y aprobada. ## 7) Criterio de cierre de la fase 1 + La fase 1 se cierra cuando: + - la causa raíz de cada check está documentada, - queda definido el SSoT por dominio, - los ADRs están registrados y aceptados, - el plan de Fase 2 está explícito y no depende de inferencias de código. ## 8) Implementación aplicada en la Fase 2 + - Ajustado el workflow `.github/workflows/validate-access-control-drift.yml` para dispararse en cambios relevantes y soportar `workflow_dispatch` sin caer en `No jobs were run`. - Reparado el defecto sintáctico y la regresión del bloque de pruebas de IPFS que impedía compilar TypeScript. - Reforzado el manejo de CIDs en `frontend/src/services/ipfs.ts` para permitir test fixtures de ejemplo sin perder la validación de CIDs plausibles reales. - Se mantiene la política de diseño del monorepo: `contracts/token-factory/src/lib.rs` sigue siendo la fuente de verdad, con el frontend y la documentación validándose en CI. ## 9) Cierre de la Fase 4: publicación y PR + - Se valida el estado del repositorio, el árbol limpio y la rama lista para publicación. - El SSOT queda actualizado con la evidencia final de QA y cierre del entregable. - La rama se publica en el fork `origin` para abrir la solicitud de extracción hacia `upstream/main`. diff --git a/docs/context/issue-1118-analytics-adr005-mapping-context.md b/docs/context/issue-1118-analytics-adr005-mapping-context.md index 6676f414..6095966b 100644 --- a/docs/context/issue-1118-analytics-adr005-mapping-context.md +++ b/docs/context/issue-1118-analytics-adr005-mapping-context.md @@ -30,26 +30,26 @@ ### Requisitos normalizados y matriz ADR -> evidencia -| ID | Requisito de ADR-005 | Evidencia actual | Cobertura | Gap / decisión | -|---|---|---|---|---| -| `REQ-ADR005-01` | No recopilar PII ni direcciones de wallet. | `UT-06` comprueba tipos de props escalares; los tests ejercitan `symbol`, `amount` y `success`. | Parcial | Ampliar tests con una lista explícita de campos prohibidos y revisión de todos los callers. No waiver: es una garantía de privacidad. | -| `REQ-ADR005-02` | No usar cookies, fingerprinting ni tracking cross-site. | Ninguna aserción en las dos suites; el CI no inspecciona cookies ni configuración del proveedor. | No cubierta por tests | Mantener la afirmación como propiedad del proveedor y añadir un check documental/configuracional en Fase 2. No waiver para cookies propias; documentar el límite de verificación sobre Plausible. | -| `REQ-ADR005-03` | El opt-out debe estar disponible cuando analytics está configurado. | `CT-01` renderiza el checkbox con dominio; `CT-02` verifica que se oculta sin dominio. | Cubierta | Sin ampliación requerida; añadir anotación ADR en la implementación del test. | -| `REQ-ADR005-04` | Persistir la preferencia en `localStorage` bajo `analytics_opt_out`. | `UT-04`, `UT-05`, `CT-05`, `CT-06` verifican escritura, eliminación y lectura persistida. | Cubierta | Añadir caso de almacenamiento no disponible si se busca cubrir la tolerancia declarada por el servicio. | -| `REQ-ADR005-05` | Leer el consentimiento en cada tracking call y aplicar el cambio inmediatamente en la sesión. | `UT-08`, `UT-09`, `UT-14`, `UT-15`, `UT-18`, `CT-07`, `CT-08` cubren supresión y reactivación sin reload. | Cubierta | Sin waiver. Conservar pruebas de transición opt-in/opt-out. | -| `REQ-ADR005-06` | Enviar únicamente `pageview` y eventos custom con nombre y props no-PII. | `UT-06`, `UT-07`, `UT-10`, `UT-11`, `UT-12`, `UT-13` verifican forma de llamadas y pageview con URL. | Parcial | Añadir catálogo verificable de nombres/eventos permitidos o justificar que el nombre es input controlado por callers. Validar que la URL no incorpora wallet. | -| `REQ-ADR005-07` | No realizar llamadas si `VITE_PLAUSIBLE_DOMAIN` no está configurado. | `UT-10`, `UT-16`, `CT-02` verifican ausencia de llamadas/renderizado. | Cubierta | Sin ampliación requerida; cubrir también dominio whitespace si la política lo exige. | -| `REQ-ADR005-08` | Todo tracking debe pasar por `trackEvent`/`trackPageView`; no se permite `window.plausible` directo. | `CI-01` rechaza imports directos fuera de allowlist; `CI-02` rechaza llamadas `window.plausible`; `UT-17`, `UT-18` cubren API pública. | Cubierta con limitación | Fase 2 debe hacer que CI también verifique la existencia y ejecución de sus tests. La allowlist de `App.tsx` requiere revisión explícita ante cambios. | +| ID | Requisito de ADR-005 | Evidencia actual | Cobertura | Gap / decisión | +| --------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `REQ-ADR005-01` | No recopilar PII ni direcciones de wallet. | `UT-06` comprueba tipos de props escalares; los tests ejercitan `symbol`, `amount` y `success`. | Parcial | Ampliar tests con una lista explícita de campos prohibidos y revisión de todos los callers. No waiver: es una garantía de privacidad. | +| `REQ-ADR005-02` | No usar cookies, fingerprinting ni tracking cross-site. | Ninguna aserción en las dos suites; el CI no inspecciona cookies ni configuración del proveedor. | No cubierta por tests | Mantener la afirmación como propiedad del proveedor y añadir un check documental/configuracional en Fase 2. No waiver para cookies propias; documentar el límite de verificación sobre Plausible. | +| `REQ-ADR005-03` | El opt-out debe estar disponible cuando analytics está configurado. | `CT-01` renderiza el checkbox con dominio; `CT-02` verifica que se oculta sin dominio. | Cubierta | Sin ampliación requerida; añadir anotación ADR en la implementación del test. | +| `REQ-ADR005-04` | Persistir la preferencia en `localStorage` bajo `analytics_opt_out`. | `UT-04`, `UT-05`, `CT-05`, `CT-06` verifican escritura, eliminación y lectura persistida. | Cubierta | Añadir caso de almacenamiento no disponible si se busca cubrir la tolerancia declarada por el servicio. | +| `REQ-ADR005-05` | Leer el consentimiento en cada tracking call y aplicar el cambio inmediatamente en la sesión. | `UT-08`, `UT-09`, `UT-14`, `UT-15`, `UT-18`, `CT-07`, `CT-08` cubren supresión y reactivación sin reload. | Cubierta | Sin waiver. Conservar pruebas de transición opt-in/opt-out. | +| `REQ-ADR005-06` | Enviar únicamente `pageview` y eventos custom con nombre y props no-PII. | `UT-06`, `UT-07`, `UT-10`, `UT-11`, `UT-12`, `UT-13` verifican forma de llamadas y pageview con URL. | Parcial | Añadir catálogo verificable de nombres/eventos permitidos o justificar que el nombre es input controlado por callers. Validar que la URL no incorpora wallet. | +| `REQ-ADR005-07` | No realizar llamadas si `VITE_PLAUSIBLE_DOMAIN` no está configurado. | `UT-10`, `UT-16`, `CT-02` verifican ausencia de llamadas/renderizado. | Cubierta | Sin ampliación requerida; cubrir también dominio whitespace si la política lo exige. | +| `REQ-ADR005-08` | Todo tracking debe pasar por `trackEvent`/`trackPageView`; no se permite `window.plausible` directo. | `CI-01` rechaza imports directos fuera de allowlist; `CI-02` rechaza llamadas `window.plausible`; `UT-17`, `UT-18` cubren API pública. | Cubierta con limitación | Fase 2 debe hacer que CI también verifique la existencia y ejecución de sus tests. La allowlist de `App.tsx` requiere revisión explícita ante cambios. | ### Matriz inversa evidencia -> requisito -| Evidencia | Requisitos protegidos | Observación | -|---|---|---| -| `analytics.test.ts` (`UT-01` a `UT-05`) | `REQ-ADR005-03`, `REQ-ADR005-04` | La suite del servicio cubre estado y persistencia, no UI. | -| `analytics.test.ts` (`UT-06` a `UT-13`) | `REQ-ADR005-01`, `REQ-ADR005-06`, `REQ-ADR005-07` | La restricción de tipos no constituye por sí sola una prueba exhaustiva de PII. | -| `analytics.test.ts` (`UT-14` a `UT-18`) | `REQ-ADR005-05`, `REQ-ADR005-07`, `REQ-ADR005-08` | Cubre supresión inmediata y ausencia de API global, no todos los callers productivos. | -| `AnalyticsOptOut.test.tsx` (`CT-01` a `CT-09`) | `REQ-ADR005-03`, `REQ-ADR005-04`, `REQ-ADR005-05` | Confirma accesibilidad básica mediante `aria-label`; no prueba integración en footer/App. | -| `check-analytics-bypass.mjs` (`CI-01`, `CI-02`) | `REQ-ADR005-08` | Escanea `.ts/.tsx`, omite tests y aplica una allowlist explícita. No prueba privacidad del payload. | +| Evidencia | Requisitos protegidos | Observación | +| ----------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| `analytics.test.ts` (`UT-01` a `UT-05`) | `REQ-ADR005-03`, `REQ-ADR005-04` | La suite del servicio cubre estado y persistencia, no UI. | +| `analytics.test.ts` (`UT-06` a `UT-13`) | `REQ-ADR005-01`, `REQ-ADR005-06`, `REQ-ADR005-07` | La restricción de tipos no constituye por sí sola una prueba exhaustiva de PII. | +| `analytics.test.ts` (`UT-14` a `UT-18`) | `REQ-ADR005-05`, `REQ-ADR005-07`, `REQ-ADR005-08` | Cubre supresión inmediata y ausencia de API global, no todos los callers productivos. | +| `AnalyticsOptOut.test.tsx` (`CT-01` a `CT-09`) | `REQ-ADR005-03`, `REQ-ADR005-04`, `REQ-ADR005-05` | Confirma accesibilidad básica mediante `aria-label`; no prueba integración en footer/App. | +| `check-analytics-bypass.mjs` (`CI-01`, `CI-02`) | `REQ-ADR005-08` | Escanea `.ts/.tsx`, omite tests y aplica una allowlist explícita. No prueba privacidad del payload. | ## Gap Analysis y Enforcement @@ -147,16 +147,16 @@ Para un test que cubra varios requisitos se usará una línea por requisito. El ### Matriz de validación final -| Requisito | Resultado QA | Evidencia | Estado formal | -|---|---|---|---| -| `REQ-ADR005-01` No PII ni wallets | Payload escalar y ausencia de wallet verificados; auditoría de callers pendiente | `analytics.test.ts`, revisión de payload | Parcial | -| `REQ-ADR005-02` Sin cookies/fingerprinting/cross-site tracking | No cubierto por unit tests; falta evidencia de navegador/red y proveedor | Requiere QA de integración | Bloqueado | -| `REQ-ADR005-03` Opt-out disponible | Renderizado y accesibilidad pasan | `AnalyticsOptOut.test.tsx` | Aprobado | -| `REQ-ADR005-04` Persistencia `analytics_opt_out` | Escritura, eliminación, relectura y reset simulado pasan | Ambas suites | Aprobado | -| `REQ-ADR005-05` Efecto inmediato | Supresión/reactivación y toggle spam pasan | Ambas suites | Aprobado | -| `REQ-ADR005-06` Payload pageview/custom no-PII | Forma y props escalares pasan; catálogo de eventos sigue abierto | `analytics.test.ts` | Parcial | -| `REQ-ADR005-07` Dominio ausente deshabilita analytics | Cero llamadas y control oculto pasan | Ambas suites | Aprobado | -| `REQ-ADR005-08` Cero bypasses | Script CI pasa con cero violaciones | `check-analytics-bypass.mjs` | Aprobado | +| Requisito | Resultado QA | Evidencia | Estado formal | +| -------------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------- | ------------- | +| `REQ-ADR005-01` No PII ni wallets | Payload escalar y ausencia de wallet verificados; auditoría de callers pendiente | `analytics.test.ts`, revisión de payload | Parcial | +| `REQ-ADR005-02` Sin cookies/fingerprinting/cross-site tracking | No cubierto por unit tests; falta evidencia de navegador/red y proveedor | Requiere QA de integración | Bloqueado | +| `REQ-ADR005-03` Opt-out disponible | Renderizado y accesibilidad pasan | `AnalyticsOptOut.test.tsx` | Aprobado | +| `REQ-ADR005-04` Persistencia `analytics_opt_out` | Escritura, eliminación, relectura y reset simulado pasan | Ambas suites | Aprobado | +| `REQ-ADR005-05` Efecto inmediato | Supresión/reactivación y toggle spam pasan | Ambas suites | Aprobado | +| `REQ-ADR005-06` Payload pageview/custom no-PII | Forma y props escalares pasan; catálogo de eventos sigue abierto | `analytics.test.ts` | Parcial | +| `REQ-ADR005-07` Dominio ausente deshabilita analytics | Cero llamadas y control oculto pasan | Ambas suites | Aprobado | +| `REQ-ADR005-08` Cero bypasses | Script CI pasa con cero violaciones | `check-analytics-bypass.mjs` | Aprobado | ### Veredicto diff --git a/docs/contract-abi.md b/docs/contract-abi.md index 71005235..1705de76 100644 --- a/docs/contract-abi.md +++ b/docs/contract-abi.md @@ -351,10 +351,10 @@ Read the current split (empty map means no split). Propose a new admin address. The current admin calls this to name a successor. The proposal is stored in `FactoryState` and expires after `ADMIN_PROPOSAL_TTL_LEDGERS` ledgers (~28 hours at 6 seconds/ledger). If a second proposal is issued before the first is accepted or cancelled, it **overwrites** the first, resetting the expiry. -| Param | Type | Description | -| --------------- | --------- | ------------------------------------------------------------- | -| `current_admin` | `Address` | Current admin; must authorize this call. | -| `new_admin` | `Address` | Proposed successor. Must differ from `current_admin`. | +| Param | Type | Description | +| --------------- | --------- | ----------------------------------------------------- | +| `current_admin` | `Address` | Current admin; must authorize this call. | +| `new_admin` | `Address` | Proposed successor. Must differ from `current_admin`. | Emits `adm_prop` with `(current_admin, new_admin, expiry_ledger)`. @@ -364,15 +364,16 @@ Errors: `Unauthorized` if caller is not the current admin; `InvalidParameters` f Complete a pending rotation. **The proposed admin** calls this, proving they control the proposed key. Only succeeds when a live (non-expired) proposal exists for `new_admin`. -| Param | Type | Description | -| ----------- | --------- | -------------------------------------------------------------------- | -| `new_admin` | `Address` | The address that was named in the most recent `propose_admin` call. | +| Param | Type | Description | +| ----------- | --------- | ------------------------------------------------------------------- | +| `new_admin` | `Address` | The address that was named in the most recent `propose_admin` call. | Emits `adm_acc` with `(old_admin, new_admin)` on success. Errors: -- `NoPendingProposal` (code 24) — no proposal is pending, or `new_admin` does not match the proposed address. -- `ProposalExpired` (code 25) — the proposal's expiry ledger has passed. The expired proposal is cleared from state; the current admin must issue a new `propose_admin` call. + +- `NoPendingProposal` (code 26) — no proposal is pending, or `new_admin` does not match the proposed address. +- `ProposalExpired` (code 27) — the proposal's expiry ledger has passed. The rejection reverts the call, so the expired proposal stays on record but can never be accepted; the current admin clears it with `cancel_admin_proposal` or replaces it with a new `propose_admin` call. ### `cancel_admin_proposal(current_admin)` @@ -423,35 +424,35 @@ Read-only: returns `true` if `address` is on the whitelist. ## Errors -| Code | Symbol | When | -| ---- | --------------------------- | ------------------------------------------------------------------------------------- | -| 1 | `InsufficientFee` | `fee_payment < required_fee` | -| 2 | `Unauthorized` | caller is not allowed for this operation | -| 3 | `InvalidParameters` | argument out of range or malformed | -| 4 | `TokenNotFound` | unknown token index or address | -| 5 | `MetadataAlreadySet` | _(deprecated — retained for ABI compatibility; no longer returned by `set_metadata`)_ | -| 6 | `AlreadyInitialized` | double-initialize attempt | -| 7 | `BurnAmountExceedsBalance` | `burn` > balance | -| 8 | `BurnNotEnabled` | burning on a token that has been disabled | -| 9 | `InvalidBurnAmount` | zero or negative burn | -| 10 | `ContractPaused` | operation blocked because factory is paused | -| 11 | `Reentrancy` | concurrent reentrant call detected | -| 12 | `ArithmeticOverflow` | checked-op failed | -| 13 | `StateNotFound` | factory not yet initialized | -| 14 | `InvalidTokenParams` | name/symbol validation failed during token creation | -| 15 | `InvalidDecimals` | decimals outside `[0, 18]` | -| 16 | `MaxSupplyExceeded` | mint would exceed cap | -| 17 | `InvalidFeeSplit` | `set_fee_split` map bps do not sum to 10_000 | -| 18 | `TooManyFeeSplitRecipients` | `set_fee_split` map has more than `MAX_FEE_SPLIT_RECIPIENTS` (10) recipients | -| 19 | `AlreadyBackfilled` | `backfill_capped_supply` already applied for this token | -| 20 | `NotWhitelisted` | creator is not on the whitelist when enforcement is enabled | -| 21 | `InvalidMetadataUri` | URI is empty, missing `ipfs://` prefix, exceeds 128 bytes, or has no CID | -| 22 | `ZeroFeeSplitEntry` | `set_fee_split` map contains an entry with `bps == 0` | -| 23 | `MetadataFrozen` | metadata is frozen (via `freeze_metadata` or auto-freeze after max updates) | -| 24 | `TreasuryTransferFailed` | payment/redirect of a fee share to `treasury` itself failed (no further fallback) | -| 24 | `BatchSizeExceeded` | `create_tokens_batch` called with more than `MAX_BATCH_SIZE` (20) tokens | -| 24 | `NoPendingProposal` | `accept_admin` called with no live proposal, or the caller is not the proposed address | -| 25 | `ProposalExpired` | the pending proposal's expiry ledger has passed; current admin must re-propose | +| Code | Symbol | When | +| ---- | --------------------------- | -------------------------------------------------------------------------------------- | +| 1 | `InsufficientFee` | `fee_payment < required_fee` | +| 2 | `Unauthorized` | caller is not allowed for this operation | +| 3 | `InvalidParameters` | argument out of range or malformed | +| 4 | `TokenNotFound` | unknown token index or address | +| 5 | `MetadataAlreadySet` | _(deprecated — retained for ABI compatibility; no longer returned by `set_metadata`)_ | +| 6 | `AlreadyInitialized` | double-initialize attempt | +| 7 | `BurnAmountExceedsBalance` | `burn` > balance | +| 8 | `BurnNotEnabled` | burning on a token that has been disabled | +| 9 | `InvalidBurnAmount` | zero or negative burn | +| 10 | `ContractPaused` | operation blocked because factory is paused | +| 11 | `Reentrancy` | concurrent reentrant call detected | +| 12 | `ArithmeticOverflow` | checked-op failed | +| 13 | `StateNotFound` | factory not yet initialized | +| 14 | `InvalidTokenParams` | name/symbol validation failed during token creation | +| 15 | `InvalidDecimals` | decimals outside `[0, 18]` | +| 16 | `MaxSupplyExceeded` | mint would exceed cap | +| 17 | `InvalidFeeSplit` | `set_fee_split` map bps do not sum to 10_000 | +| 18 | `TooManyFeeSplitRecipients` | `set_fee_split` map has more than `MAX_FEE_SPLIT_RECIPIENTS` (10) recipients | +| 19 | `AlreadyBackfilled` | `backfill_capped_supply` already applied for this token | +| 20 | `NotWhitelisted` | creator is not on the whitelist when enforcement is enabled | +| 21 | `InvalidMetadataUri` | URI is empty, missing `ipfs://` prefix, exceeds 128 bytes, or has no CID | +| 22 | `ZeroFeeSplitEntry` | `set_fee_split` map contains an entry with `bps == 0` | +| 23 | `MetadataFrozen` | metadata is frozen (via `freeze_metadata` or auto-freeze after max updates) | +| 24 | `TreasuryTransferFailed` | payment/redirect of a fee share to `treasury` itself failed (no further fallback) | +| 25 | `BatchSizeExceeded` | `create_tokens_batch` called with more than `MAX_BATCH_SIZE` (20) tokens | +| 26 | `NoPendingProposal` | `accept_admin` called with no live proposal, or the caller is not the proposed address | +| 27 | `ProposalExpired` | the pending proposal's expiry ledger has passed; current admin must re-propose | ## Test/fuzz-only helpers @@ -461,27 +462,27 @@ Read-only: returns `true` if `address` is on the whitelist. The contract emits Soroban events on a `(factory, action)` topic. The frontend parses them via `frontend/src/services/stellar-impl.ts`. Events: -| Action | Payload | Trigger | -| ----------- | ---------------------------------------- | -------------------------------------- | -| `init` | `(admin)` | `initialize` | -| `init` | `(admin)` | `__constructor` | -| `created` | `(token_address, creator, name, symbol)` | `create_token` / `create_tokens_batch` | -| `meta` | `(token_address, metadata_uri, version)` | `set_metadata` (every update) | -| `meta_frz` | `(token_address, admin)` | `freeze_metadata` | -| `mint` | `(token_address, to, amount)` | `mint_tokens` | -| `burn` | `(token_address, from, amount)` | `burn` | -| `fees` | `(base_fee, metadata_fee)` | `update_fees` | -| `split_set` | `(admin, splits)` | `set_fee_split` (non-empty) | -| `split_clr` | `(admin)` | `set_fee_split` (empty — clears split) | -| `fee_redir` | `(recipient, share)` | `distribute_fee` (recipient `try_transfer` failed; share redirected to `treasury`) | -| `pause` | `(admin)` | `pause` | -| `unpause` | `(admin)` | `unpause` | -| `adm_prop` | `(current_admin, new_admin, expiry_ledger)` | `propose_admin` / `transfer_admin` / `update_admin` | -| `adm_acc` | `(old_admin, new_admin)` | `accept_admin` | -| `adm_can` | `(current_admin, cancelled_admin)` | `cancel_admin_proposal` | -| `wl_add` | `(address)` | `add_to_whitelist` | -| `wl_rm` | `(address)` | `remove_from_whitelist` | -| `wl_tog` | `(enabled)` | `set_whitelist_enabled` | +| Action | Payload | Trigger | +| ----------- | ------------------------------------------- | ---------------------------------------------------------------------------------- | +| `init` | `(admin)` | `initialize` | +| `init` | `(admin)` | `__constructor` | +| `created` | `(token_address, creator, name, symbol)` | `create_token` / `create_tokens_batch` | +| `meta` | `(token_address, metadata_uri, version)` | `set_metadata` (every update) | +| `meta_frz` | `(token_address, admin)` | `freeze_metadata` | +| `mint` | `(token_address, to, amount)` | `mint_tokens` | +| `burn` | `(token_address, from, amount)` | `burn` | +| `fees` | `(base_fee, metadata_fee)` | `update_fees` | +| `split_set` | `(admin, splits)` | `set_fee_split` (non-empty) | +| `split_clr` | `(admin)` | `set_fee_split` (empty — clears split) | +| `fee_redir` | `(recipient, share)` | `distribute_fee` (recipient `try_transfer` failed; share redirected to `treasury`) | +| `pause` | `(admin)` | `pause` | +| `unpause` | `(admin)` | `unpause` | +| `adm_prop` | `(current_admin, new_admin, expiry_ledger)` | `propose_admin` / `transfer_admin` / `update_admin` | +| `adm_acc` | `(old_admin, new_admin)` | `accept_admin` | +| `adm_can` | `(current_admin, cancelled_admin)` | `cancel_admin_proposal` | +| `wl_add` | `(address)` | `add_to_whitelist` | +| `wl_rm` | `(address)` | `remove_from_whitelist` | +| `wl_tog` | `(enabled)` | `set_whitelist_enabled` | ## Batch creation UI diff --git a/docs/incident-response.md b/docs/incident-response.md index 4929313e..b3cb11eb 100644 --- a/docs/incident-response.md +++ b/docs/incident-response.md @@ -27,15 +27,15 @@ The factory contract's `admin` address is a single point of catastrophic trust. An attacker in possession of the admin key can: -| Action | Effect | -|---|---| -| `update_fees(admin, base_fee, metadata_fee)` | Set arbitrarily high fees to drain users who call the contract | -| `set_fee_split(admin, splits)` | Redirect collected fees to an attacker-controlled address | -| `upgrade(admin, new_wasm_hash)` | Replace the contract with arbitrary attacker code | -| `propose_admin(admin, attacker_address)` | Begin a rotation to an attacker-controlled address; the attacker then calls `accept_admin` to complete the transfer | -| `pause(admin)` | Halt the factory, denying service to all token creators | +| Action | Effect | +| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `update_fees(admin, base_fee, metadata_fee)` | Set arbitrarily high fees to drain users who call the contract | +| `set_fee_split(admin, splits)` | Redirect collected fees to an attacker-controlled address | +| `upgrade(admin, new_wasm_hash)` | Replace the contract with arbitrary attacker code | +| `propose_admin(admin, attacker_address)` | Begin a rotation to an attacker-controlled address; the attacker then calls `accept_admin` to complete the transfer | +| `pause(admin)` | Halt the factory, denying service to all token creators | -**Two-step rotation reduces but does not eliminate admin-rotation risk.** The two-step model (`propose_admin` + `accept_admin`) prevents accidental rotation to an uncontrolled address — the incoming key must prove it can sign. However, an attacker who already holds the current admin key can still complete the rotation to their own address by controlling both steps. Detection window: a `propose_admin` call emits an `adm_prop` event that is visible on-chain *before* `accept_admin` completes the transfer, giving operators a window to cancel via `cancel_admin_proposal` if the proposal is unauthorized. +**Two-step rotation reduces but does not eliminate admin-rotation risk.** The two-step model (`propose_admin` + `accept_admin`) prevents accidental rotation to an uncontrolled address — the incoming key must prove it can sign. However, an attacker who already holds the current admin key can still complete the rotation to their own address by controlling both steps. Detection window: a `propose_admin` call emits an `adm_prop` event that is visible on-chain _before_ `accept_admin` completes the transfer, giving operators a window to cancel via `cancel_admin_proposal` if the proposal is unauthorized. **Upgrade detection gap:** `upgrade` currently emits no on-chain event (see issue #9). Until event emission is added, detection of a malicious WASM swap requires active polling of the on-chain WASM hash. This runbook treats upgrade detection latency as high-risk and calls it out explicitly. @@ -48,12 +48,14 @@ Detection relies on multiple independent signals. Any single signal is enough to ### 2.1 Sentry error correlation (fastest for client-side anomalies) All Sentry events captured during transaction lifecycles are tagged with `network`, `contractId`, and `functionName` (see issue #944). An unusual spike in: + - `functionName: deployToken` errors with `InsufficientFee` codes (fee manipulation) - `functionName: pollTransaction` failures across many unrelated users should trigger investigation of the admin state. Set a Sentry alert rule: + - Filter: `network = mainnet`, `functionName = deployToken`, `code = InsufficientFee` - Condition: event count > 3 in 5 minutes - Action: page on-call channel immediately @@ -67,6 +69,7 @@ curl -N "https://horizon.stellar.org/accounts//operations?curs ``` Alert on: + - Any `adm_prop` event (admin rotation proposed — act immediately if unexpected; you have until `accept_admin` is called or the proposal expires to cancel via `cancel_admin_proposal`) - Any `adm_acc` event (admin rotation completed — if unexpected, the admin key is compromised) - Any `fees` event with unusually large values @@ -103,13 +106,13 @@ Token creators reporting sudden fee increases or failed `create_token` calls wit Maintain a live copy of this table in a private team channel. Do not embed real names or personal contact details in this public document. -| Role | Responsibility | Contact | -|---|---|---| -| **Incident commander** | Declares the incident, coordinates all actions, is the single decision-maker | *See team contact list* | -| **Admin key custodian** | Has access to the hardware wallet / multisig device holding the admin key | *See team contact list* | -| **Break-glass custodian** | Has access to the backup admin (break-glass) account | *See team contact list* | -| **Communications lead** | Drafts and publishes user-facing notices | *See team contact list* | -| **Legal / compliance** | Advises on disclosure obligations | *See team contact list* | +| Role | Responsibility | Contact | +| ------------------------- | ---------------------------------------------------------------------------- | ----------------------- | +| **Incident commander** | Declares the incident, coordinates all actions, is the single decision-maker | _See team contact list_ | +| **Admin key custodian** | Has access to the hardware wallet / multisig device holding the admin key | _See team contact list_ | +| **Break-glass custodian** | Has access to the backup admin (break-glass) account | _See team contact list_ | +| **Communications lead** | Drafts and publishes user-facing notices | _See team contact list_ | +| **Legal / compliance** | Advises on disclosure obligations | _See team contact list_ | Minimum team size for executing on-chain recovery: **two people** (incident commander + admin key custodian). Never execute admin-level transactions alone. @@ -169,6 +172,7 @@ stellar contract invoke \ If the admin key is still operable but you suspect imminent key-theft (e.g. private key was exposed in logs), rotate to the pre-agreed break-glass account using the two-step flow: **Step 4a — Propose the break-glass address as new admin:** + ```bash stellar contract invoke \ --id "$FACTORY_CONTRACT_ID" \ @@ -180,6 +184,7 @@ stellar contract invoke \ ``` **Step 4b — Accept from the break-glass account (must be done within ~28 hours):** + ```bash stellar contract invoke \ --id "$FACTORY_CONTRACT_ID" \ @@ -267,6 +272,7 @@ If the hashes differ and no authorised upgrade was performed, treat the contract ### 6.2 Re-audit admin key custody Before unpausing the factory, conduct an emergency review of how the admin key was compromised: + - Was it stored insecurely (clipboard, environment variable, unencrypted file)? - Was the hardware wallet device physically accessed? - Was phishing involved? @@ -278,6 +284,7 @@ Document findings and apply remediation before resuming operations. A `upgrade` to attacker-controlled WASM is the most severe scenario. The existing contract at the original address is now malicious and **must not be used**. Recovery steps: + 1. Deploy a **new** factory contract at a fresh contract address. 2. Re-initialize with the new admin address. 3. Notify all integrators and the frontend config must be updated. @@ -286,6 +293,7 @@ Recovery steps: ### 6.4 Unpause Only unpause after: + - [ ] Admin key custody is restored to a known-good state. - [ ] WASM integrity is confirmed against the known-good hash. - [ ] Fee configuration is verified to be correct. @@ -309,18 +317,19 @@ This section documents the pre-agreed backup admin account that allows recovery ### 7.1 What the break-glass account is The break-glass account is a **separate Stellar keypair** held by a designated break-glass custodian. It is never used for routine operations. Its sole purpose is to receive admin rights via `transfer_admin` in an emergency, then: + 1. Pause the factory. 2. Transfer admin to a freshly-generated recovery key. 3. Facilitate any necessary fee or WASM restoration. ### 7.2 Custody requirements -| Requirement | Detail | -|---|---| -| Storage | Hardware wallet (Ledger or equivalent) held by the break-glass custodian | -| Location | Physically separate from the primary admin hardware wallet | -| Access | Break-glass custodian only; known to the incident commander | -| Testing | Confirmed usable (non-zero XLM balance, key unlocked) at least once per quarter | +| Requirement | Detail | +| ----------- | ------------------------------------------------------------------------------- | +| Storage | Hardware wallet (Ledger or equivalent) held by the break-glass custodian | +| Location | Physically separate from the primary admin hardware wallet | +| Access | Break-glass custodian only; known to the incident commander | +| Testing | Confirmed usable (non-zero XLM balance, key unlocked) at least once per quarter | ### 7.3 Setting up the break-glass address @@ -401,6 +410,7 @@ Document any differences as potential attacker modifications. ### 8.2 Full deployment log audit Review: + - When did the admin key leave the hardware wallet? - Which machines accessed it? - What processes had `ADMIN_SECRET_KEY` in their environment? @@ -420,12 +430,12 @@ Review: ### 8.5 Disclosure timeline -| Time | Action | -|---|---| -| T+0 | Incident declared, factory paused | -| T+1 h | Internal post-mortem started | -| T+24 h | Initial public notice posted (see below) | -| T+72 h | Full incident report published | +| Time | Action | +| ------ | ----------------------------------------- | +| T+0 | Incident declared, factory paused | +| T+1 h | Internal post-mortem started | +| T+24 h | Initial public notice posted (see below) | +| T+72 h | Full incident report published | | T+30 d | Follow-up confirming remediation complete | > Note: StellarForge operates in the "emerging markets fintech-adjacent" space. Depending on the jurisdiction of affected users and the scale of financial impact, applicable data-breach or financial-services notification laws may set shorter or stricter timelines than those above. Consult Legal before publishing the T+24 h notice. diff --git a/docs/metadata-format.md b/docs/metadata-format.md index a8d39c26..f038cf12 100644 --- a/docs/metadata-format.md +++ b/docs/metadata-format.md @@ -93,16 +93,16 @@ Pinata API credentials (`PINATA_API_KEY`, `PINATA_API_SECRET`) live in the **ser ## Where these are enforced -| Layer | Location | Notes | -| --- | --- | --- | +| Layer | Location | Notes | +| ------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------- | | Integrity (authoritative) | `verifyCIDMatch()` in `frontend/src/services/ipfs.ts` | Verifies CID matches content before parsing; rejects on mismatch | -| Read (authoritative) | `getMetadata` in `frontend/src/services/ipfs.ts` | The only check that binds for externally-pinned metadata | -| Write (advisory) | `MetadataForm.tsx`, `MetadataUploadForm.tsx` | Better UX; trivially bypassed by pinning directly | -| Render (defence in depth) | `TokenDetail.tsx`, `TokenExplorer.tsx` | Bounds height regardless of character count | -| Layer | Location | Notes | -| ------------------------- | ------------------------------------------------ | -------------------------------------------------------- | -| Read (authoritative) | `getMetadata` in `frontend/src/services/ipfs.ts` | The only check that binds for externally-pinned metadata | -| Write (advisory) | `MetadataForm.tsx`, `MetadataUploadForm.tsx` | Better UX; trivially bypassed by pinning directly | -| Render (defence in depth) | `TokenDetail.tsx`, `TokenExplorer.tsx` | Bounds height regardless of character count | +| Read (authoritative) | `getMetadata` in `frontend/src/services/ipfs.ts` | The only check that binds for externally-pinned metadata | +| Write (advisory) | `MetadataForm.tsx`, `MetadataUploadForm.tsx` | Better UX; trivially bypassed by pinning directly | +| Render (defence in depth) | `TokenDetail.tsx`, `TokenExplorer.tsx` | Bounds height regardless of character count | +| Layer | Location | Notes | +| ------------------------- | ------------------------------------------------ | -------------------------------------------------------- | +| Read (authoritative) | `getMetadata` in `frontend/src/services/ipfs.ts` | The only check that binds for externally-pinned metadata | +| Write (advisory) | `MetadataForm.tsx`, `MetadataUploadForm.tsx` | Better UX; trivially bypassed by pinning directly | +| Render (defence in depth) | `TokenDetail.tsx`, `TokenExplorer.tsx` | Bounds height regardless of character count | Constants live in `frontend/src/services/ipfs.ts` as `MAX_METADATA_NAME_LENGTH` and `MAX_METADATA_DESCRIPTION_LENGTH`. Update this document if you change them. diff --git a/docs/token-wasm-provenance.md b/docs/token-wasm-provenance.md index 22d32104..5bf844db 100644 --- a/docs/token-wasm-provenance.md +++ b/docs/token-wasm-provenance.md @@ -18,12 +18,12 @@ The StellarForge factory contract takes a `token_wasm_hash` parameter at initial The deployment guide in `README.md` (Step 4 — "Upload Token Contract WASM") identifies the intended token WASM as: -| Field | Value | -|---|---| -| Repository | `stellar/soroban-examples` | -| File path | `token/target/wasm32-unknown-unknown/release/soroban_token_contract.wasm` | -| Interface | SEP-41 (Soroban Token Interface) | -| SDK version pinned in factory | `soroban-sdk = "26.1.0"`, `soroban-token-sdk = "26.1.0"` | +| Field | Value | +| ----------------------------- | ------------------------------------------------------------------------- | +| Repository | `stellar/soroban-examples` | +| File path | `token/target/wasm32-unknown-unknown/release/soroban_token_contract.wasm` | +| Interface | SEP-41 (Soroban Token Interface) | +| SDK version pinned in factory | `soroban-sdk = "26.1.0"`, `soroban-token-sdk = "26.1.0"` | This is the canonical example token contract published by Stellar Development Foundation (SDF) as a reference implementation of SEP-41. @@ -59,10 +59,10 @@ The following should be understood by every deployer: ## Deployment log (fill this in before mainnet) -| Environment | Network | WASM source tag/commit | WASM hash (hex) | Audit status | Decision owner | Date | -|---|---|---|---|---|---|---| -| testnet | testnet | `soroban-examples` @ _tag_ | _64-hex_ | Not audited — reference impl, internal review | _name_ | _date_ | -| mainnet | mainnet | `soroban-examples` @ _tag_ | _64-hex_ | **TODO before launch** | _name_ | _date_ | +| Environment | Network | WASM source tag/commit | WASM hash (hex) | Audit status | Decision owner | Date | +| ----------- | ------- | -------------------------- | --------------- | --------------------------------------------- | -------------- | ------ | +| testnet | testnet | `soroban-examples` @ _tag_ | _64-hex_ | Not audited — reference impl, internal review | _name_ | _date_ | +| mainnet | mainnet | `soroban-examples` @ _tag_ | _64-hex_ | **TODO before launch** | _name_ | _date_ | --- diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 41dbbad9..0a82e75a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,9 +11,8 @@ "@sentry/react": "^10.70.0", "@stellar/freighter-api": "^6.0.1", "@tailwindcss/postcss": "^4.3.3", - "i18next": "^26.3.6", - "multiformats": "^13.1.0", "i18next": "^26.4.0", + "multiformats": "^13.1.0", "qrcode.react": "^4.2.0", "react": "^19.2.8", "react-dom": "^19.2.8", @@ -3318,9 +3317,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3335,9 +3331,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3352,9 +3345,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3369,9 +3359,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3386,9 +3373,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3403,9 +3387,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3420,9 +3401,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3437,9 +3415,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/frontend/package.json b/frontend/package.json index 70d0c0f8..441a5480 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,9 +27,8 @@ "@sentry/react": "^10.70.0", "@stellar/freighter-api": "^6.0.1", "@tailwindcss/postcss": "^4.3.3", - "i18next": "^26.3.6", - "multiformats": "^13.1.0", "i18next": "^26.4.0", + "multiformats": "^13.1.0", "qrcode.react": "^4.2.0", "react": "^19.2.8", "react-dom": "^19.2.8", diff --git a/frontend/scripts/check-analytics-bypass.mjs b/frontend/scripts/check-analytics-bypass.mjs index d13cb411..3fa58514 100644 --- a/frontend/scripts/check-analytics-bypass.mjs +++ b/frontend/scripts/check-analytics-bypass.mjs @@ -61,8 +61,7 @@ const TEST_FILE_PATTERN = /\.test\.(ts|tsx)$/ // ---------------------------------------------------------------------------- /** Import that pulls trackEvent or trackPageView directly from analytics.ts */ -const DIRECT_IMPORT_RE = - /from\s+['"][^'"]*services\/analytics['"]/ +const DIRECT_IMPORT_RE = /from\s+['"][^'"]*services\/analytics['"]/ /** Direct call to window.plausible (bypasses isEnabled check entirely) */ const WINDOW_PLAUSIBLE_RE = /window\.plausible\s*\??\s*\(/ @@ -82,7 +81,8 @@ function walkTs(dir) { const full = join(dir, entry) const stat = statSync(full) if (stat.isDirectory()) { - if (entry === 'node_modules' || entry === '__tests__' && full.includes('node_modules')) continue + if (entry === 'node_modules' || (entry === '__tests__' && full.includes('node_modules'))) + continue results.push(...walkTs(full)) } else if (['.ts', '.tsx'].includes(extname(full))) { results.push(full) @@ -159,9 +159,9 @@ function main() { console.error( ' To fix: replace direct service/plausible usage with the useAnalytics hook\n' + - ' or route the call through trackEvent() / trackPageView() which enforce consent.\n' + - ' If the usage is intentional (e.g., a new allowed file), add it to ALLOWED_PATHS\n' + - ' in scripts/check-analytics-bypass.mjs with a comment explaining the exception.\n', + ' or route the call through trackEvent() / trackPageView() which enforce consent.\n' + + ' If the usage is intentional (e.g., a new allowed file), add it to ALLOWED_PATHS\n' + + ' in scripts/check-analytics-bypass.mjs with a comment explaining the exception.\n', ) process.exit(1) diff --git a/frontend/src/services/stellar-impl.test.ts b/frontend/src/services/stellar-impl.test.ts index 1055cf28..a5ba1c61 100644 --- a/frontend/src/services/stellar-impl.test.ts +++ b/frontend/src/services/stellar-impl.test.ts @@ -63,11 +63,28 @@ const XDR = { topic1: 'AAAADwAAAAd1bnBhdXNlAA==', value: 'AAAAEAAAAAEAAAABAAAAEgAAAAAAAAAA/7SpxpEMV33pXktl+ZP53F+vX2pv4CdwdZDOdAw7Z/k=', }, - adm_upd: { - topic1: 'AAAADwAAAAdhZG1fdXBkAA==', + // Admin rotation is two-step: adm_prop (proposed) → adm_acc (accepted), + // or adm_can (cancelled by the current admin). There is no adm_upd topic. + adm_prop: { + topic1: 'AAAADwAAAAhhZG1fcHJvcA==', + value: + 'AAAAEAAAAAEAAAADAAAAEgAAAAAAAAAA/7SpxpEMV33pXktl+ZP53F+vX2pv4CdwdZDOdAw7Z/kAAAASAAAAAAAAAAB7ANe3xwFAZ5WBGpHb4OKOc//iQMFL1TPn/ZAo86i36QAAAAUAAAAAAAAH0A==', + }, + adm_acc: { + topic1: 'AAAADwAAAAdhZG1fYWNjAA==', value: 'AAAAEAAAAAEAAAACAAAAEgAAAAAAAAAA/7SpxpEMV33pXktl+ZP53F+vX2pv4CdwdZDOdAw7Z/kAAAASAAAAAAAAAAB7ANe3xwFAZ5WBGpHb4OKOc//iQMFL1TPn/ZAo86i36Q==', }, + adm_can: { + topic1: 'AAAADwAAAAdhZG1fY2FuAA==', + value: + 'AAAAEAAAAAEAAAACAAAAEgAAAAAAAAAA/7SpxpEMV33pXktl+ZP53F+vX2pv4CdwdZDOdAw7Z/kAAAASAAAAAAAAAAB7ANe3xwFAZ5WBGpHb4OKOc//iQMFL1TPn/ZAo86i36Q==', + }, + fee_redir: { + topic1: 'AAAADwAAAAlmZWVfcmVkaXIAAAA=', + value: + 'AAAAEAAAAAEAAAACAAAAEgAAAAAAAAAAewDXt8cBQGeVgRqR2+DijnP/4kDBS9Uz5/2QKPOot+kAAAAKAAAAAAAAAAAAAAAAAA9CQA==', + }, } as const // ── Helpers ─────────────────────────────────────────────────────────────────── @@ -105,26 +122,32 @@ describe('CONTRACT_TOPIC_MAP', () => { 'mint', 'burn', 'fees', + 'fee_redir', 'split_set', 'split_clr', 'pause', 'unpause', - 'adm_upd', + 'adm_prop', + 'adm_acc', + 'adm_can', 'wl_add', 'wl_rm', 'wl_tog', ] as const - it('contains exactly the fifteen contract topics', () => { + it('contains exactly the eighteen contract topics', () => { expect(Object.keys(CONTRACT_TOPIC_MAP).sort()).toEqual([...EXPECTED_TOPICS].sort()) }) - it('maps adm_upd to adm_upd (not admin_update)', () => { - expect(CONTRACT_TOPIC_MAP['adm_upd']).toBe('adm_upd') + it('maps each two-step admin-rotation topic to itself', () => { + expect(CONTRACT_TOPIC_MAP['adm_prop']).toBe('adm_prop') + expect(CONTRACT_TOPIC_MAP['adm_acc']).toBe('adm_acc') + expect(CONTRACT_TOPIC_MAP['adm_can']).toBe('adm_can') }) - it('does NOT contain the legacy admin_update key', () => { + it('does NOT contain the legacy admin_update or single-step adm_upd keys', () => { expect(CONTRACT_TOPIC_MAP).not.toHaveProperty('admin_update') + expect(CONTRACT_TOPIC_MAP).not.toHaveProperty('adm_upd') }) }) @@ -144,7 +167,7 @@ describe('parseRpcEvent – edge cases', () => { it('returns null for an unrecognised topic (e.g. admin_update)', async () => { // The old, incorrect topic string that used to be in the frontend const unknownTopic = 'AAAADwAAAAxhZG1pbl91cGRhdGU=' // scvSymbol("admin_update") - const raw = makeRaw('adm_upd', { topic: [FACTORY_TOPIC, unknownTopic] }) + const raw = makeRaw('adm_acc', { topic: [FACTORY_TOPIC, unknownTopic] }) expect(await parseRpcEvent(raw)).toBeNull() }) @@ -254,28 +277,47 @@ describe('parseRpcEvent – unpause', () => { }) }) -// ── parseRpcEvent – adm_upd (THE KEY REGRESSION TEST) ──────────────────────── +// ── parseRpcEvent – admin rotation (THE KEY REGRESSION TESTS) ─────────────── -describe('parseRpcEvent – adm_upd (admin rotation)', () => { +describe('parseRpcEvent – admin rotation (adm_prop / adm_acc / adm_can)', () => { /** - * This is the regression test for the adm_upd vs admin_update mismatch. + * These are the regression tests for the admin-topic mismatch. * - * Before the fix, the frontend EVENT_TOPICS contained 'admin_update' while - * the contract emits symbol_short!("adm_upd"). The decoded topic 'adm_upd' - * was not in the allow-list, so parseRpcEvent returned null and every - * admin-rotation event was silently dropped from Transaction History and - * CSV exports. + * The frontend EVENT_TOPICS first contained 'admin_update', then the + * single-step 'adm_upd'; the contract now performs a two-step rotation and + * emits symbol_short!("adm_prop") / ("adm_acc") / ("adm_can"). A decoded + * topic missing from the allow-list makes parseRpcEvent return null, so + * every admin-rotation event is silently dropped from Transaction History + * and CSV exports. */ - it('decodes an adm_upd event — the critical admin-rotation regression', async () => { - const result = await parseRpcEvent(makeRaw('adm_upd')) + it('decodes an adm_prop event — a rotation proposed but not yet accepted', async () => { + const result = await parseRpcEvent(makeRaw('adm_prop')) expect(result).not.toBeNull() - expect(result!.type).toBe('adm_upd') + expect(result!.type).toBe('adm_prop') expect(result!.data.currentAdmin).toBe(ADDR1) expect(result!.data.newAdmin).toBe(ADDR2) + // The expiry ledger tells a watcher when the proposal lapses. + expect(result!.data.expiryLedger).toBe('2000') + }) + + it('decodes an adm_acc event — the rotation that actually changes the admin', async () => { + const result = await parseRpcEvent(makeRaw('adm_acc')) + expect(result).not.toBeNull() + expect(result!.type).toBe('adm_acc') + expect(result!.data.currentAdmin).toBe(ADDR1) + expect(result!.data.newAdmin).toBe(ADDR2) + }) + + it('decodes an adm_can event — a pending proposal cancelled', async () => { + const result = await parseRpcEvent(makeRaw('adm_can')) + expect(result).not.toBeNull() + expect(result!.type).toBe('adm_can') + expect(result!.data.currentAdmin).toBe(ADDR1) + expect(result!.data.cancelledAdmin).toBe(ADDR2) }) it('preserves both admin addresses in the data payload', async () => { - const result = await parseRpcEvent(makeRaw('adm_upd')) + const result = await parseRpcEvent(makeRaw('adm_acc')) // Both must be present and distinct — this is the information that // users and auditors need to audit who controls the factory. expect(result!.data.currentAdmin).not.toBe(result!.data.newAdmin) @@ -286,22 +328,40 @@ describe('parseRpcEvent – adm_upd (admin rotation)', () => { it('returns null for the legacy admin_update topic string (no regression back)', async () => { // Verify that the raw string "admin_update" is never silently accepted const legacyTopic = 'AAAADwAAAAxhZG1pbl91cGRhdGU=' // scvSymbol("admin_update") - const raw = makeRaw('adm_upd', { topic: [FACTORY_TOPIC, legacyTopic] }) + const raw = makeRaw('adm_acc', { topic: [FACTORY_TOPIC, legacyTopic] }) + expect(await parseRpcEvent(raw)).toBeNull() + }) + + it('returns null for the retired single-step adm_upd topic string', async () => { + const retiredTopic = 'AAAADwAAAAdhZG1fdXBkAA==' // scvSymbol("adm_upd") + const raw = makeRaw('adm_acc', { topic: [FACTORY_TOPIC, retiredTopic] }) expect(await parseRpcEvent(raw)).toBeNull() }) }) +// ── parseRpcEvent – fee redirect ───────────────────────────────────────────── + +describe('parseRpcEvent – fee_redir (fee share redirected to treasury)', () => { + it('decodes the skipped recipient and the redirected amount', async () => { + const result = await parseRpcEvent(makeRaw('fee_redir')) + expect(result).not.toBeNull() + expect(result!.type).toBe('fee_redir') + expect(result!.data.recipient).toBe(ADDR2) + expect(result!.data.amount).toBe('1000000') + }) +}) + // ── CSV serialization includes admin rotation ───────────────────────────────── -describe('adm_upd CSV serialization', () => { +describe('admin-rotation CSV serialization', () => { /** - * Verify that once an adm_upd event is parsed, serializeTransactionsToCSV + * Verify that once an admin-rotation event is parsed, serializeTransactionsToCSV * would capture it. We test the data shape because the CSV util operates * on TransactionHistoryItem (Horizon op model), but we can verify the parsed * event has the right shape to be mapped to a CSV row. */ - it('parsed adm_upd event has currentAdmin and newAdmin in data', async () => { - const result = await parseRpcEvent(makeRaw('adm_upd')) + it('parsed adm_acc event has currentAdmin and newAdmin in data', async () => { + const result = await parseRpcEvent(makeRaw('adm_acc')) expect(result).not.toBeNull() // These fields must be present for a UI row to show both addresses expect(Object.keys(result!.data)).toContain('currentAdmin') diff --git a/frontend/src/services/stellar-impl.ts b/frontend/src/services/stellar-impl.ts index 66428137..3a99c804 100644 --- a/frontend/src/services/stellar-impl.ts +++ b/frontend/src/services/stellar-impl.ts @@ -429,16 +429,27 @@ function scValToString(val: xdr.ScVal | undefined): string { * leaving holes in the audit trail this table is supposed to reconstruct * (issue #917). * - * Audit of all fifteen contract topics (lib.rs → frontend): + * Admin rotation is two-step, so there is no single `adm_upd` topic: the + * contract emits `adm_prop` when a rotation is proposed, `adm_acc` when the + * proposed admin accepts it, and `adm_can` when the current admin cancels a + * pending proposal. + * + * Audit of all eighteen contract topics (lib.rs → frontend): * init → 'init' (factory init) * created → 'created' (token deployed) * meta → 'meta' (metadata URI set) + * meta_frz → 'meta_frz' (metadata frozen) * mint → 'mint' (tokens minted) * burn → 'burn' (tokens burned) * fees → 'fees' (fees updated) + * fee_redir → 'fee_redir' (fee share redirected to treasury) + * split_set → 'split_set' (fee split configured) + * split_clr → 'split_clr' (fee split cleared) * pause → 'pause' (factory paused) * unpause → 'unpause' (factory unpaused) - * adm_upd → 'adm_upd' (admin rotated) ← was incorrectly 'admin_update' + * adm_prop → 'adm_prop' (admin rotation proposed) + * adm_acc → 'adm_acc' (admin rotation accepted — admin changed) + * adm_can → 'adm_can' (pending admin rotation cancelled) * wl_add → 'wl_add' (address added to whitelist) * wl_rm → 'wl_rm' (address removed from whitelist) * wl_tog → 'wl_tog' (whitelist enforcement toggled) @@ -451,11 +462,14 @@ export const CONTRACT_TOPIC_MAP: Record = { mint: 'mint', burn: 'burn', fees: 'fees', + fee_redir: 'fee_redir', split_set: 'split_set', split_clr: 'split_clr', pause: 'pause', unpause: 'unpause', - adm_upd: 'adm_upd', + adm_prop: 'adm_prop', + adm_acc: 'adm_acc', + adm_can: 'adm_can', wl_add: 'wl_add', wl_rm: 'wl_rm', wl_tog: 'wl_tog', @@ -509,10 +523,23 @@ export async function parseRpcEvent(raw: RpcEventResponse): Promise 0: @@ -185,6 +213,15 @@ detect_creator_auth() { fn_contains_pattern "$lib_rs_file" "creator\\.require_auth" > "$output_file" } +# Rule A2b: Detect stored-creator identity check (e.g., creator != admin). +# `set_metadata` names its caller `admin`, but the guard compares it against +# the token's stored creator — factory-admin privilege grants nothing here. +detect_creator_check() { + local lib_rs_file="$1" + local output_file="$2" + fn_contains_pattern "$lib_rs_file" "creator\\s*!=\\s*admin" > "$output_file" +} + # Rule A3: Detect admin identity check (e.g., state.admin != admin) detect_admin_check() { local lib_rs_file="$1" @@ -254,6 +291,7 @@ build_actual_claims() { # Apply detection rules detect_admin_auth "$lib_rs_file" "${temp_dir}/admin_auth_fns.txt" detect_creator_auth "$lib_rs_file" "${temp_dir}/creator_auth_fns.txt" + detect_creator_check "$lib_rs_file" "${temp_dir}/creator_check_fns.txt" detect_admin_check "$lib_rs_file" "${temp_dir}/admin_check_fns.txt" detect_whitelist_gate "$lib_rs_file" "${temp_dir}/whitelist_gate_fns.txt" @@ -268,6 +306,7 @@ build_actual_claims() { # Check each rule grep -q "^${fn}$" "${temp_dir}/admin_auth_fns.txt" 2>/dev/null && claims+=("admin_auth") grep -q "^${fn}$" "${temp_dir}/creator_auth_fns.txt" 2>/dev/null && claims+=("creator_auth") + grep -q "^${fn}$" "${temp_dir}/creator_check_fns.txt" 2>/dev/null && claims+=("creator_check") grep -q "^${fn}$" "${temp_dir}/admin_check_fns.txt" 2>/dev/null && claims+=("admin_check") grep -q "^${fn}$" "${temp_dir}/whitelist_gate_fns.txt" 2>/dev/null && claims+=("whitelist_gate") diff --git a/scripts/check-kiro-specs.mjs b/scripts/check-kiro-specs.mjs index 26113e28..3c9e7e15 100644 --- a/scripts/check-kiro-specs.mjs +++ b/scripts/check-kiro-specs.mjs @@ -1,11 +1,11 @@ -import fs from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const ROOT_DIR = path.resolve(__dirname, ".."); -const SPECS_DIR = path.join(ROOT_DIR, ".kiro", "specs"); +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const ROOT_DIR = path.resolve(__dirname, '..') +const SPECS_DIR = path.join(ROOT_DIR, '.kiro', 'specs') /** * Checks all .kiro/specs/* directories to ensure no spec directory sits indefinitely @@ -15,51 +15,49 @@ const SPECS_DIR = path.join(ROOT_DIR, ".kiro", "specs"); * @returns {{ errors: string[], checkedDirs: string[] }} */ export function checkKiroSpecs(specsDir = SPECS_DIR) { - const errors = []; - const checkedDirs = []; + const errors = [] + const checkedDirs = [] if (!fs.existsSync(specsDir)) { - return { errors: [`Specs directory does not exist: ${specsDir}`], checkedDirs: [] }; + return { errors: [`Specs directory does not exist: ${specsDir}`], checkedDirs: [] } } - const entries = fs.readdirSync(specsDir, { withFileTypes: true }); + const entries = fs.readdirSync(specsDir, { withFileTypes: true }) for (const entry of entries) { - if (!entry.isDirectory()) continue; + if (!entry.isDirectory()) continue - const dirName = entry.name; - const dirPath = path.join(specsDir, dirName); - checkedDirs.push(dirName); + const dirName = entry.name + const dirPath = path.join(specsDir, dirName) + checkedDirs.push(dirName) - const files = fs.readdirSync(dirPath); + const files = fs.readdirSync(dirPath) // Filter out .config.kiro and hidden files to check for actual spec/resolution content - const docFiles = files.filter( - (f) => f !== ".config.kiro" && !f.startsWith(".") - ); + const docFiles = files.filter((f) => f !== '.config.kiro' && !f.startsWith('.')) if (files.length === 0) { - errors.push(`.kiro/specs/${dirName} is empty.`); + errors.push(`.kiro/specs/${dirName} is empty.`) } else if (docFiles.length === 0) { errors.push( - `.kiro/specs/${dirName} contains only .config.kiro and no specification or status document (e.g. requirements.md).` - ); + `.kiro/specs/${dirName} contains only .config.kiro and no specification or status document (e.g. requirements.md).`, + ) } } - return { errors, checkedDirs }; + return { errors, checkedDirs } } if (process.argv[1] === __filename) { - const { errors, checkedDirs } = checkKiroSpecs(); + const { errors, checkedDirs } = checkKiroSpecs() if (errors.length > 0) { - console.error("❌ Kiro specs check failed:"); + console.error('❌ Kiro specs check failed:') for (const err of errors) { - console.error(` - ${err}`); + console.error(` - ${err}`) } - process.exit(1); + process.exit(1) } console.log( - `✅ Checked ${checkedDirs.length} .kiro/specs directories. All spec directories contain specification or status documentation.` - ); + `✅ Checked ${checkedDirs.length} .kiro/specs directories. All spec directories contain specification or status documentation.`, + ) } diff --git a/scripts/check-kiro-specs.test.mjs b/scripts/check-kiro-specs.test.mjs index 92b4013e..f30a3e10 100644 --- a/scripts/check-kiro-specs.test.mjs +++ b/scripts/check-kiro-specs.test.mjs @@ -1,42 +1,42 @@ -import { describe, it } from "node:test"; -import assert from "node:assert/strict"; -import fs from "node:fs"; -import path from "node:path"; -import os from "node:os"; -import { checkKiroSpecs } from "./check-kiro-specs.mjs"; +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +import os from 'node:os' +import { checkKiroSpecs } from './check-kiro-specs.mjs' -describe("check-kiro-specs", () => { - it("passes when spec directory has requirements.md and .config.kiro", () => { - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kiro-test-")); - const specDir = path.join(tmpDir, "sample-spec"); - fs.mkdirSync(specDir, { recursive: true }); - fs.writeFileSync(path.join(specDir, ".config.kiro"), "{}"); - fs.writeFileSync(path.join(specDir, "requirements.md"), "# Spec"); +describe('check-kiro-specs', () => { + it('passes when spec directory has requirements.md and .config.kiro', () => { + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kiro-test-')) + const specDir = path.join(tmpDir, 'sample-spec') + fs.mkdirSync(specDir, { recursive: true }) + fs.writeFileSync(path.join(specDir, '.config.kiro'), '{}') + fs.writeFileSync(path.join(specDir, 'requirements.md'), '# Spec') - const { errors, checkedDirs } = checkKiroSpecs(tmpDir); - assert.deepEqual(errors, []); - assert.deepEqual(checkedDirs, ["sample-spec"]); + const { errors, checkedDirs } = checkKiroSpecs(tmpDir) + assert.deepEqual(errors, []) + assert.deepEqual(checkedDirs, ['sample-spec']) - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); + fs.rmSync(tmpDir, { recursive: true, force: true }) + }) - it("fails when a spec directory contains only .config.kiro", () => { - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kiro-test-")); - const specDir = path.join(tmpDir, "stub-spec"); - fs.mkdirSync(specDir, { recursive: true }); - fs.writeFileSync(path.join(specDir, ".config.kiro"), "{}"); + it('fails when a spec directory contains only .config.kiro', () => { + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kiro-test-')) + const specDir = path.join(tmpDir, 'stub-spec') + fs.mkdirSync(specDir, { recursive: true }) + fs.writeFileSync(path.join(specDir, '.config.kiro'), '{}') - const { errors, checkedDirs } = checkKiroSpecs(tmpDir); - assert.equal(errors.length, 1); - assert.match(errors[0], /contains only \.config\.kiro/); - assert.deepEqual(checkedDirs, ["stub-spec"]); + const { errors, checkedDirs } = checkKiroSpecs(tmpDir) + assert.equal(errors.length, 1) + assert.match(errors[0], /contains only \.config\.kiro/) + assert.deepEqual(checkedDirs, ['stub-spec']) - fs.rmSync(tmpDir, { recursive: true, force: true }); - }); + fs.rmSync(tmpDir, { recursive: true, force: true }) + }) - it("validates the checked-in .kiro/specs directory in repository", () => { - const { errors, checkedDirs } = checkKiroSpecs(); - assert.deepEqual(errors, []); - assert.ok(checkedDirs.length >= 11, "Should check all spec directories"); - }); -}); + it('validates the checked-in .kiro/specs directory in repository', () => { + const { errors, checkedDirs } = checkKiroSpecs() + assert.deepEqual(errors, []) + assert.ok(checkedDirs.length >= 11, 'Should check all spec directories') + }) +}) diff --git a/scripts/check-stellar-impl-abi.mjs b/scripts/check-stellar-impl-abi.mjs index 15478b9c..dd4571e2 100644 --- a/scripts/check-stellar-impl-abi.mjs +++ b/scripts/check-stellar-impl-abi.mjs @@ -117,7 +117,9 @@ function extractContractCalls(content) { } if (parenDepth !== 0) { - console.warn(`WARNING: Could not find matching paren for ${functionName} at line ${lineNumber}`) + console.warn( + `WARNING: Could not find matching paren for ${functionName} at line ${lineNumber}`, + ) continue } @@ -208,7 +210,9 @@ function validate() { // (e.g., method vs function syntax, receiver implicit vs explicit). // In a real parser, we'd do proper AST matching. if (Math.abs(argumentCount - expectedArgCount) <= 1) { - console.log(`✓ ${functionName} at ${location}: ${argumentCount} args (expected ~${expectedArgCount})`) + console.log( + `✓ ${functionName} at ${location}: ${argumentCount} args (expected ~${expectedArgCount})`, + ) } else { console.error( `✗ ${functionName} at ${location}: ${argumentCount} args, expected ~${expectedArgCount}`,