diff --git a/.env.example b/.env.example index 1c3ec76..cdb457b 100644 --- a/.env.example +++ b/.env.example @@ -54,8 +54,11 @@ STELLAR_SECRET_KEY=SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Public key corresponding to STELLAR_SECRET_KEY. STELLAR_PUBLIC_KEY=GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -# Deployed contract IDs (fill in after deploying contracts). -STELLAR_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# Deployed contract IDs (fill in after deploying contracts; these are the same +# keys written to contract-ids.env by the deploy scripts). +STELLAR_CONTRACT_VAULT_REGISTRY=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +STELLAR_CONTRACT_ACCESS_LEASE=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +STELLAR_CONTRACT_SUBSCRIPTION=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # ----------------------------------------------------------------------------- diff --git a/docs/DEPLOY-BACKEND-GUIDE.md b/docs/DEPLOY-BACKEND-GUIDE.md index 9a75542..2ffcbd4 100644 --- a/docs/DEPLOY-BACKEND-GUIDE.md +++ b/docs/DEPLOY-BACKEND-GUIDE.md @@ -140,8 +140,9 @@ Add each variable below. Click **+ New Variable** for each one. | `PAY_TO` | `GCK7ALS7EP5DQG4UZMON3XTNUE7SSIW27XW24UOLXDHBOHWEWIGZVPZF` | Your BACKEND wallet public key | | `AGENT_SECRET_KEY` | `` | Your BACKEND wallet secret key | | `REGISTRY_SECRET_KEY` | `` | Same as AGENT_SECRET_KEY | -| `VAULT_REGISTRY_CONTRACT_ID` | `CBQEIMSRPSRKJJHGOELZTP3CISZVHZ6WPKZTWJMYZXHFXPGHHWFQBD4H` | Deployed contract | -| `REGISTRY_CONTRACT_ID` | `CBQEIMSRPSRKJJHGOELZTP3CISZVHZ6WPKZTWJMYZXHFXPGHHWFQBD4H` | Same as above | +| `STELLAR_CONTRACT_VAULT_REGISTRY` | `CBQEIMSRPSRKJJHGOELZTP3CISZVHZ6WPKZTWJMYZXHFXPGHHWFQBD4H` | Deployed contract (from `contract-ids.env`) | +| `STELLAR_CONTRACT_ACCESS_LEASE` | `CDQZBCEPN6RCJAQLEKB3ZRNLUZXDCCFMVIS6STZNAOEAQLXD3FUBNQGX` | Deployed contract (from `contract-ids.env`) | +| `STELLAR_CONTRACT_SUBSCRIPTION` | `CCCE6Q6WHDICGMQWXXXMM6X7YDGK3BXU4JNQJNSIA6XQRC52MQL42CD6` | Deployed contract (from `contract-ids.env`) | | `OPENROUTER_API_KEY` | Get a free key at [openrouter.ai](https://openrouter.ai) | Free tier available | | `ADMIN_API_KEY` | `` | Keep this secret | @@ -173,8 +174,9 @@ USDC_CONTRACT_ID=CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA PAY_TO=GCK7ALS7EP5DQG4UZMON3XTNUE7SSIW27XW24UOLXDHBOHWEWIGZVPZF AGENT_SECRET_KEY= REGISTRY_SECRET_KEY= -VAULT_REGISTRY_CONTRACT_ID=CBQEIMSRPSRKJJHGOELZTP3CISZVHZ6WPKZTWJMYZXHFXPGHHWFQBD4H -REGISTRY_CONTRACT_ID=CBQEIMSRPSRKJJHGOELZTP3CISZVHZ6WPKZTWJMYZXHFXPGHHWFQBD4H +STELLAR_CONTRACT_VAULT_REGISTRY=CBQEIMSRPSRKJJHGOELZTP3CISZVHZ6WPKZTWJMYZXHFXPGHHWFQBD4H +STELLAR_CONTRACT_ACCESS_LEASE=CDQZBCEPN6RCJAQLEKB3ZRNLUZXDCCFMVIS6STZNAOEAQLXD3FUBNQGX +STELLAR_CONTRACT_SUBSCRIPTION=CCCE6Q6WHDICGMQWXXXMM6X7YDGK3BXU4JNQJNSIA6XQRC52MQL42CD6 OPENROUTER_API_KEY=sk-or-... ← FILL IN (get free at openrouter.ai) ADMIN_API_KEY= NODE_ENV=production diff --git a/docs/ENVIRONMENT-VARIABLES.md b/docs/ENVIRONMENT-VARIABLES.md index a570e1c..79176f7 100644 --- a/docs/ENVIRONMENT-VARIABLES.md +++ b/docs/ENVIRONMENT-VARIABLES.md @@ -39,9 +39,9 @@ This document is the single source of truth for every environment variable used | `PAY_TO` | Yes | — | Backend | | `AGENT_SECRET_KEY` | Yes | — | Backend | | `REGISTRY_SECRET_KEY` | Yes | — | Backend | -| `VAULT_REGISTRY_CONTRACT_ID` | Yes | — | Backend | -| `REGISTRY_CONTRACT_ID` | Yes | — | Backend | | `STELLAR_CONTRACT_VAULT_REGISTRY` | Yes | — | Backend | +| `VAULT_REGISTRY_CONTRACT_ID` | No | — | Backend (deprecated alias) | +| `REGISTRY_CONTRACT_ID` | No | — | Backend (deprecated alias) | | `STELLAR_CONTRACT_ACCESS_LEASE` | Yes | — | Backend | | `STELLAR_CONTRACT_SUBSCRIPTION` | Yes | — | Backend | | `STELLAR_SECRET_KEY` | Yes | — | Backend / Scripts | @@ -140,21 +140,11 @@ This document is the single source of truth for every environment variable used - **Default:** none - **Format:** `G...` (56-character Stellar public key) -### `VAULT_REGISTRY_CONTRACT_ID` -- **Purpose:** Contract ID of the vault registry contract. -- **Required:** Yes -- **Default:** none - -### `REGISTRY_CONTRACT_ID` -- **Purpose:** Contract ID of the primary registry contract. -- **Required:** Yes -- **Default:** none - ### `STELLAR_CONTRACT_VAULT_REGISTRY` - **Purpose:** Contract ID for the vault registry (used by deployment scripts and backend). - **Required:** Yes - **Default:** none -- **Notes:** May be identical to `VAULT_REGISTRY_CONTRACT_ID`; keep both for backward compatibility with existing scripts. +- **Notes:** Canonical name; written to `contract-ids.env` by both deploy paths. The legacy aliases below are normalised to this key by `rollback-contracts.cjs`. ### `STELLAR_CONTRACT_ACCESS_LEASE` - **Purpose:** Contract ID for the access-lease contract. @@ -166,6 +156,18 @@ This document is the single source of truth for every environment variable used - **Required:** Yes - **Default:** none +### `VAULT_REGISTRY_CONTRACT_ID` *(deprecated alias)* +- **Purpose:** Legacy alias of `STELLAR_CONTRACT_VAULT_REGISTRY`. +- **Required:** No +- **Default:** none +- **Notes:** Retained only for backward compatibility with older scripts; new deployments should use `STELLAR_CONTRACT_VAULT_REGISTRY`. + +### `REGISTRY_CONTRACT_ID` *(deprecated alias)* +- **Purpose:** Legacy alias of `STELLAR_CONTRACT_VAULT_REGISTRY`. +- **Required:** No +- **Default:** none +- **Notes:** Retained only for backward compatibility with older scripts; new deployments should use `STELLAR_CONTRACT_VAULT_REGISTRY`. + --- ## Secrets & API Keys @@ -348,8 +350,6 @@ These variables are consumed by the deployment manifests rather than by the appl | `PAY_TO` | Dev `G...` account | Staging `G...` account | Prod `G...` account | | `AGENT_SECRET_KEY` | Dev `S...` key | Staging `S...` key | Prod `S...` key (secret manager) | | `REGISTRY_SECRET_KEY` | Dev `S...` key | Staging `S...` key | Prod `S...` key (secret manager) | -| `VAULT_REGISTRY_CONTRACT_ID` | Dev contract ID | Staging contract ID | Prod contract ID | -| `REGISTRY_CONTRACT_ID` | Dev contract ID | Staging contract ID | Prod contract ID | | `STELLAR_CONTRACT_VAULT_REGISTRY` | Dev contract ID | Staging contract ID | Prod contract ID | | `STELLAR_CONTRACT_ACCESS_LEASE` | Dev contract ID | Staging contract ID | Prod contract ID | | `STELLAR_CONTRACT_SUBSCRIPTION` | Dev contract ID | Staging contract ID | Prod contract ID | @@ -401,8 +401,6 @@ USDC_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Contracts # --------------------------------------------------------------------------- PAY_TO=GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -VAULT_REGISTRY_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -REGISTRY_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX STELLAR_CONTRACT_VAULT_REGISTRY=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX STELLAR_CONTRACT_ACCESS_LEASE=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX STELLAR_CONTRACT_SUBSCRIPTION=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/docs/contract-deploy-guide.md b/docs/contract-deploy-guide.md index 468d1ba..ab21ceb 100644 --- a/docs/contract-deploy-guide.md +++ b/docs/contract-deploy-guide.md @@ -192,12 +192,12 @@ Then redeploy the backend (Railway redeploys automatically on env change). ```bash # Read vault-registry count soroban contract invoke \ - --id $vault_registry --source deployer --network testnet \ + --id $STELLAR_CONTRACT_VAULT_REGISTRY --source deployer --network testnet \ -- count # Grant a test lease (30 days = 518400 ledgers) soroban contract invoke \ - --id $access_lease --source deployer --network testnet \ + --id $STELLAR_CONTRACT_ACCESS_LEASE --source deployer --network testnet \ -- grant_lease \ --resource_id "test-resource-1" \ --buyer GBUYER1_PUBLIC_KEY \ @@ -205,7 +205,7 @@ soroban contract invoke \ # Check if valid soroban contract invoke \ - --id $access_lease --source deployer --network testnet \ + --id $STELLAR_CONTRACT_ACCESS_LEASE --source deployer --network testnet \ -- is_valid \ --resource_id "test-resource-1" \ --buyer GBUYER1_PUBLIC_KEY diff --git a/scripts/03-deploy-contracts.sh b/scripts/03-deploy-contracts.sh index f775fca..68f59a9 100644 --- a/scripts/03-deploy-contracts.sh +++ b/scripts/03-deploy-contracts.sh @@ -13,7 +13,8 @@ # export CONTRACTS_DIR=../contracts # optional; defaults to ../contracts # bash scripts/03-deploy-contracts.sh # -# Output: contract-ids.env (source this before running 04-init-contracts.sh) +# Output: contract-ids.env (canonical STELLAR_CONTRACT_* keys; source this +# before running 04-init-contracts.sh) set -euo pipefail @@ -60,9 +61,10 @@ WASM_DIR="$CONTRACTS_DIR/target/wasm32-unknown-unknown/release" # ── Helper: deploy one contract ─────────────────────────────────────────────── deploy_contract() { - local name="$1" + local env_name="$1" + local name="$2" local wasm="$WASM_DIR/${name}.wasm" - # Progress goes to stderr; only `name=id` goes to stdout (and the env file). + # Progress goes to stderr; only `ENV_NAME=id` goes to stdout (and the env file). echo "" >&2 echo "▸ Deploying $name…" >&2 local id @@ -71,14 +73,14 @@ deploy_contract() { --source deployer \ --network testnet) echo " Contract ID: $id" >&2 - echo "$name=$id" + echo "$env_name=$id" } # ── Deploy ──────────────────────────────────────────────────────────────────── { - deploy_contract "vault_registry" - deploy_contract "access_lease" - deploy_contract "subscription" + deploy_contract "STELLAR_CONTRACT_VAULT_REGISTRY" "vault_registry" + deploy_contract "STELLAR_CONTRACT_ACCESS_LEASE" "access_lease" + deploy_contract "STELLAR_CONTRACT_SUBSCRIPTION" "subscription" } > "$OUT_FILE" echo "" diff --git a/scripts/04-init-contracts.sh b/scripts/04-init-contracts.sh index a4ed2be..3e2e466 100644 --- a/scripts/04-init-contracts.sh +++ b/scripts/04-init-contracts.sh @@ -2,7 +2,8 @@ # SynapsVault — Step 4: Initialise all deployed contracts # # Prerequisites: -# source contract-ids.env (sets vault_registry, access_lease, subscription) +# source contract-ids.env (sets STELLAR_CONTRACT_VAULT_REGISTRY, +# STELLAR_CONTRACT_ACCESS_LEASE, STELLAR_CONTRACT_SUBSCRIPTION) # export DEPLOYER_SECRET=S... # export BACKEND_PUBLIC=G... (the backend platform wallet public key) # @@ -10,9 +11,9 @@ set -euo pipefail -: "${vault_registry:? source contract-ids.env first}" -: "${access_lease:? source contract-ids.env first}" -: "${subscription:? source contract-ids.env first}" +: "${STELLAR_CONTRACT_VAULT_REGISTRY:? source contract-ids.env first}" +: "${STELLAR_CONTRACT_ACCESS_LEASE:? source contract-ids.env first}" +: "${STELLAR_CONTRACT_SUBSCRIPTION:? source contract-ids.env first}" : "${DEPLOYER_SECRET:? export DEPLOYER_SECRET}" : "${BACKEND_PUBLIC:? export BACKEND_PUBLIC}" @@ -31,7 +32,7 @@ printf '%s\n' "$DEPLOYER_SECRET" | $CLI keys add deployer --secret-key 2>/dev/nu echo "" echo "▸ Initialising vault-registry (admin = BACKEND_PUBLIC)…" $CLI contract invoke \ - --id "$vault_registry" \ + --id "$STELLAR_CONTRACT_VAULT_REGISTRY" \ --source deployer \ --network testnet \ -- init \ @@ -42,7 +43,7 @@ echo "✅ vault-registry initialised" echo "" echo "▸ Initialising access-lease (admin = BACKEND_PUBLIC)…" $CLI contract invoke \ - --id "$access_lease" \ + --id "$STELLAR_CONTRACT_ACCESS_LEASE" \ --source deployer \ --network testnet \ -- init \ @@ -53,7 +54,7 @@ echo "✅ access-lease initialised" echo "" echo "▸ Initialising subscription manager (admin = BACKEND_PUBLIC)…" $CLI contract invoke \ - --id "$subscription" \ + --id "$STELLAR_CONTRACT_SUBSCRIPTION" \ --source deployer \ --network testnet \ -- init \ @@ -64,7 +65,7 @@ echo "✅ subscription initialised" echo "" echo "▸ Verifying vault-registry…" COUNT=$($CLI contract invoke \ - --id "$vault_registry" \ + --id "$STELLAR_CONTRACT_VAULT_REGISTRY" \ --source deployer \ --network testnet \ -- count 2>/dev/null || echo "0") @@ -78,9 +79,9 @@ echo "╚═══════════════════════ echo "" echo "Copy these into your backend .env:" echo "" -echo " STELLAR_CONTRACT_VAULT_REGISTRY=$vault_registry" -echo " STELLAR_CONTRACT_ACCESS_LEASE=$access_lease" -echo " STELLAR_CONTRACT_SUBSCRIPTION=$subscription" +echo " STELLAR_CONTRACT_VAULT_REGISTRY=$STELLAR_CONTRACT_VAULT_REGISTRY" +echo " STELLAR_CONTRACT_ACCESS_LEASE=$STELLAR_CONTRACT_ACCESS_LEASE" +echo " STELLAR_CONTRACT_SUBSCRIPTION=$STELLAR_CONTRACT_SUBSCRIPTION" echo " STELLAR_NETWORK=testnet" echo " STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org" echo "" diff --git a/scripts/deploy-contracts.cjs b/scripts/deploy-contracts.cjs index 11e2be0..3e2cf3a 100644 --- a/scripts/deploy-contracts.cjs +++ b/scripts/deploy-contracts.cjs @@ -67,6 +67,14 @@ const CONTRACTS = [ { name: 'subscription', wasmFile: 'subscription.wasm' }, ]; +// Canonical env var prefix for the deployed contract IDs (the names the backend +// reads), e.g. `vault-registry` -> `STELLAR_CONTRACT_VAULT_REGISTRY`. +const CONTRACT_ENV_PREFIX = 'STELLAR_CONTRACT_'; + +function contractEnvName(contractName) { + return `${CONTRACT_ENV_PREFIX}${contractName.toUpperCase().replace(/-/g, '_')}`; +} + // Minimum account balance (in stroops) required to proceed with deployment. const MIN_BALANCE_STROOPS = 10_000_000n; // 1 XLM @@ -490,7 +498,7 @@ function writeContractIds(contractIds, network, dryRun) { ]; for (const [name, id] of Object.entries(contractIds)) { - const envName = `${name.toUpperCase().replace(/-/g, '_')}_CONTRACT_ID`; + const envName = contractEnvName(name); lines.push(`${envName}=${id}`); } @@ -592,4 +600,4 @@ if (require.main === module) { }); } -module.exports = { parseArgs, validateEnv, CONTRACTS }; \ No newline at end of file +module.exports = { parseArgs, validateEnv, CONTRACTS, contractEnvName }; \ No newline at end of file diff --git a/scripts/rollback-contracts.cjs b/scripts/rollback-contracts.cjs index 6cbbeb8..c8b589f 100644 --- a/scripts/rollback-contracts.cjs +++ b/scripts/rollback-contracts.cjs @@ -22,6 +22,12 @@ * 2. Verifies each old contract still exists on-chain (via Soroban RPC). * 3. Updates the backend environment / ConfigMap to the previous contract IDs. * + * Contract-ID keys are normalised to the canonical `STELLAR_CONTRACT_*` names + * the backend reads, so backups written by either deploy path are supported: + * STELLAR_CONTRACT_VAULT_REGISTRY (canonical; both deploy paths) + * VAULT_REGISTRY_CONTRACT_ID (legacy SDK deployer) + * vault_registry (legacy bash deployer) + * * Usage: * node scripts/rollback-contracts.cjs \ * --backup ./backups/contract-ids.env.2024-01-01T00-00-00Z \ @@ -188,6 +194,53 @@ function isValidContractId(id) { return typeof id === 'string' && CONTRACT_ID_RE.test(id); } +// Canonical env var prefix for deployed contract IDs (the names the backend +// reads), e.g. `vault_registry` -> `STELLAR_CONTRACT_VAULT_REGISTRY`. +const CONTRACT_ENV_PREFIX = 'STELLAR_CONTRACT_'; + +// Legacy keys whose canonical target is not a plain prefix/suffix rewrite: +// `REGISTRY_CONTRACT_ID` is the older name for the vault registry contract +// (see docs/ENVIRONMENT-VARIABLES.md). +const CONTRACT_KEY_ALIASES = { + REGISTRY_CONTRACT_ID: `${CONTRACT_ENV_PREFIX}VAULT_REGISTRY`, + REGISTRY_CONTRACT: `${CONTRACT_ENV_PREFIX}VAULT_REGISTRY`, +}; + +/** + * Map any recognised contract-ID key to its canonical `STELLAR_CONTRACT_*` + * name, so backups written by any deploy path can be rolled back. + * + * Returns null when `key` is not a contract-ID reference. + */ +function canonicalContractKey(key, value) { + if (typeof key !== 'string') return null; + + if (key.startsWith(CONTRACT_ENV_PREFIX)) { + const stem = key.slice(CONTRACT_ENV_PREFIX.length); + return stem ? key : null; + } + + if (Object.prototype.hasOwnProperty.call(CONTRACT_KEY_ALIASES, key)) { + return CONTRACT_KEY_ALIASES[key]; + } + + for (const suffix of ['_CONTRACT_ID', '_CONTRACT']) { + if (key.endsWith(suffix)) { + const stem = key.slice(0, -suffix.length); + return stem ? `${CONTRACT_ENV_PREFIX}${stem}` : null; + } + } + + // Bare lower-case contract name as written by 03-deploy-contracts.sh + // (e.g. `vault_registry=C...`). Only treat it as a contract reference when + // the value is a well-formed contract ID, so ordinary settings are ignored. + if (/^[a-z][a-z0-9_]*$/.test(key) && isValidContractId(value)) { + return `${CONTRACT_ENV_PREFIX}${key.toUpperCase()}`; + } + + return null; +} + /** * Verify a contract exists on-chain by reading its instance ledger entry * (persistent `LedgerKeyContractInstance`) from Soroban RPC. @@ -237,9 +290,17 @@ function updateEnvFile(envFilePath, contractIds, dryRun) { const eq = trimmed.indexOf('='); if (eq === -1) return line; const key = trimmed.slice(0, eq).trim(); - if (Object.prototype.hasOwnProperty.call(contractIds, key)) { - seen.add(key); - return `${key}=${contractIds[key]}`; + const value = trimmed.slice(eq + 1).trim(); + const canonicalKey = canonicalContractKey(key, value); + if ( + canonicalKey && + Object.prototype.hasOwnProperty.call(contractIds, canonicalKey) + ) { + // Update canonical keys in place. Legacy aliases (e.g. + // VAULT_REGISTRY_CONTRACT_ID) are kept in sync as well, while the + // canonical key is still appended below unless already present verbatim. + if (key === canonicalKey) seen.add(canonicalKey); + return `${key}=${contractIds[canonicalKey]}`; } return line; }); @@ -320,23 +381,26 @@ async function main() { process.exit(1); } - // Only consider keys that look like contract IDs. + // Only consider keys that reference a contract ID, normalising each to its + // canonical STELLAR_CONTRACT_* name so either deploy path can be rolled back. const contractIds = {}; for (const [key, value] of Object.entries(previous)) { - if (key.endsWith('_CONTRACT_ID') || key.endsWith('_CONTRACT')) { - if (!isValidContractId(value)) { - process.stderr.write( - `[error] Backup key ${key} has invalid contract ID: ${value}\n` - ); - process.exit(1); - } - contractIds[key] = value; + const canonicalKey = canonicalContractKey(key, value); + if (!canonicalKey) continue; + if (!isValidContractId(value)) { + process.stderr.write( + `[error] Backup key ${key} has invalid contract ID: ${value}\n` + ); + process.exit(1); } + contractIds[canonicalKey] = value; } if (Object.keys(contractIds).length === 0) { process.stderr.write( - '[error] No *_CONTRACT_ID entries found in backup file.\n' + '[error] No contract ID entries found in backup file.\n' + + ' Expected STELLAR_CONTRACT_* keys, *_CONTRACT_ID keys or bare\n' + + ' contract names (vault_registry, access_lease, subscription).\n' ); process.exit(1); } @@ -412,6 +476,7 @@ module.exports = { readEnvFile, parseArgs, isValidContractId, + canonicalContractKey, contractExistsOnChain, updateEnvFile, updateConfigMap, diff --git a/test/contract-scripts.test.cjs b/test/contract-scripts.test.cjs index bd857db..a4e2f10 100644 --- a/test/contract-scripts.test.cjs +++ b/test/contract-scripts.test.cjs @@ -46,6 +46,38 @@ test('isValidContractId accepts C-addresses only', () => { assert.equal(rollback.isValidContractId(undefined), false); }); +test('canonicalContractKey normalises every deploy-path spelling', () => { + assert.equal( + rollback.canonicalContractKey('STELLAR_CONTRACT_VAULT_REGISTRY', 'x'), + 'STELLAR_CONTRACT_VAULT_REGISTRY' + ); + assert.equal( + rollback.canonicalContractKey('VAULT_REGISTRY_CONTRACT_ID', 'x'), + 'STELLAR_CONTRACT_VAULT_REGISTRY' + ); + assert.equal( + rollback.canonicalContractKey('ACCESS_LEASE_CONTRACT', 'x'), + 'STELLAR_CONTRACT_ACCESS_LEASE' + ); + assert.equal( + rollback.canonicalContractKey('REGISTRY_CONTRACT_ID', 'x'), + 'STELLAR_CONTRACT_VAULT_REGISTRY' + ); + assert.equal( + rollback.canonicalContractKey('vault_registry', VALID_ID), + 'STELLAR_CONTRACT_VAULT_REGISTRY' + ); + // Bare names are only contract references when the value is a contract ID. + assert.equal(rollback.canonicalContractKey('network', 'testnet'), null); + assert.equal(rollback.canonicalContractKey('NETWORK', 'testnet'), null); +}); + +test('deploy contractEnvName uses the canonical STELLAR_CONTRACT_* scheme', () => { + assert.equal(deploy.contractEnvName('vault-registry'), 'STELLAR_CONTRACT_VAULT_REGISTRY'); + assert.equal(deploy.contractEnvName('access-lease'), 'STELLAR_CONTRACT_ACCESS_LEASE'); + assert.equal(deploy.contractEnvName('subscription'), 'STELLAR_CONTRACT_SUBSCRIPTION'); +}); + test('rollback parseArgs requires --backup and resolves default RPC per network', () => { assert.throws(() => rollback.parseArgs([]), /--backup/); @@ -67,7 +99,7 @@ test('rollback parseArgs requires --backup and resolves default RPC per network' ); }); -test('updateEnvFile replaces existing keys, appends new ones, keeps other lines', () => { +test('updateEnvFile updates aliases, appends canonical keys, keeps other lines', () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'rollback-test-')); const file = path.join(dir, '.env'); fs.writeFileSync(file, '# keep me\nOTHER=x\nVAULT_REGISTRY_CONTRACT_ID=old\n'); @@ -77,16 +109,18 @@ test('updateEnvFile replaces existing keys, appends new ones, keeps other lines' try { rollback.updateEnvFile( file, - { VAULT_REGISTRY_CONTRACT_ID: VALID_ID, ACCESS_LEASE_CONTRACT_ID: VALID_ID }, + { STELLAR_CONTRACT_VAULT_REGISTRY: VALID_ID, STELLAR_CONTRACT_ACCESS_LEASE: VALID_ID }, false ); } finally { process.stdout.write = silence; } + // The legacy alias is kept in sync and the canonical key is appended. assert.equal( fs.readFileSync(file, 'utf8'), - `# keep me\nOTHER=x\nVAULT_REGISTRY_CONTRACT_ID=${VALID_ID}\nACCESS_LEASE_CONTRACT_ID=${VALID_ID}\n` + `# keep me\nOTHER=x\nVAULT_REGISTRY_CONTRACT_ID=${VALID_ID}\n` + + `STELLAR_CONTRACT_VAULT_REGISTRY=${VALID_ID}\nSTELLAR_CONTRACT_ACCESS_LEASE=${VALID_ID}\n` ); fs.rmSync(dir, { recursive: true, force: true }); });