Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions app/onchain/contracts/registry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Soter — Testnet Contract Registry

> Single source of truth for all Soroban contract addresses, WASM hashes, and initialization configuration deployed on **Stellar Testnet**.

---

## Files

| File | Purpose |
|---|---|
| `testnet.registry.json` | Machine-readable registry (JSON). Primary source of truth. |
| `testnet.env` | Environment-style mapping for `.env` consumption. |
| `index.ts` | Type-safe TypeScript loader for frontend/backend. |
| `update-registry.sh` | Helper script to populate the registry after a deploy. |
| `abi/` | Per-contract ABI JSON files (generated by `soroban contract inspect`). |

---

## Structure (`testnet.registry.json`)

```jsonc
{
"_meta": {
"network": "testnet",
"last_updated": "<ISO 8601>",
"deployed_at_commit": "<git SHA>",
...
},
"contracts": {
"aid_escrow": {
"contract_id": "C...", // Stellar contract address
"deployer_address": "G...", // Public key that ran the deploy
"wasm_hash": "abc123...", // SHA-256 of the uploaded WASM
"deployed_at": "<ISO 8601>",
"deployed_at_commit": "<SHA>", // Exact git commit of deployed code
"init_args": { ... } // Arguments passed to __constructor
}
},
"tokens": {
"USDC": { "contract_id": "C...", ... }
}
}
```

---

## Updating the Registry After a Deploy

### Option A — Automated (recommended)

After running `soroban contract deploy`, call the update script:

```bash
./contracts/registry/update-registry.sh \
--contract-id C... \ # output of soroban contract deploy
--deployer G... \ # your Stellar public key
--wasm-hash abc123... \ # output of soroban contract install
--admin G... # init admin address
```

The script will:
1. Capture the current `git rev-parse HEAD` and UTC timestamp automatically.
2. Patch `testnet.registry.json` in-place using `jq`.
3. Sync `testnet.env` with the same values.

### Option B — Manual

1. Open `testnet.registry.json`.
2. Replace every `REPLACE_WITH_*` placeholder under the relevant contract with real values.
3. Update `_meta.last_updated` (ISO 8601) and `_meta.deployed_at_commit` (full git SHA).
4. Mirror the changes into `testnet.env`.
5. Commit **both files** together.

---

## Using the Registry in Code

### TypeScript (frontend / backend)

```ts
import { getContractId, getTokenContractId, registry } from '../../contracts/registry'

// Get a contract address (throws if not yet deployed)
const escrowId = getContractId('aid_escrow')

// Get a token SAC address
const usdcId = getTokenContractId('USDC')

// Access full metadata
console.log(registry._meta.network_passphrase)
```

### Environment variables

```bash
source contracts/registry/testnet.env
echo $NEXT_PUBLIC_AID_ESCROW_CONTRACT_ID
```

Or copy the relevant lines into your local `.env` file.

---

## Adding a New Contract

1. Deploy the contract to Testnet.
2. Add a new entry under `contracts` in `testnet.registry.json` following the existing schema.
3. Add the corresponding env variable(s) to `testnet.env`.
4. Export a typed getter in `index.ts` if needed.
5. Open a PR — include the transaction hash in the PR description for auditability.

---

## Security Notes

- **Never commit real secret keys.** The registry stores only public keys and contract IDs.
- `testnet.env` is safe to commit (Testnet only, no secrets).
- For Mainnet, a separate `mainnet.registry.json` will be introduced — never mix the two.
Empty file.
84 changes: 84 additions & 0 deletions app/onchain/contracts/registry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* contracts/registry/index.ts
*
* Type-safe loader for the Soter Testnet Contract Registry.
* Exposes contract IDs and config to both the Next.js frontend
* and the NestJS backend without manual copy-paste.
*
* Usage:
* import { registry, getContractId } from '../../contracts/registry'
*/

import rawRegistry from './testnet.registry.json'

// ---- types ------------------------------------------------------------------

export interface ContractEntry {
contract_id: string
deployer_address: string
wasm_hash: string
deployed_at: string
deployed_at_commit: string
init_args: Record<string, unknown>
description: string
source: string
abi_path: string
}

export interface TokenEntry {
asset_code: string
issuer: string
contract_id: string
decimals: number
note: string
}

export interface RegistryMeta {
description: string
network: string
network_passphrase: string
soroban_rpc_url: string
horizon_url: string
schema_version: string
last_updated: string
deployed_at_commit: string
maintainer: string
}

export interface ContractRegistry {
_meta: RegistryMeta
contracts: Record<string, ContractEntry>
tokens: Record<string, TokenEntry>
}

// ---- exports ----------------------------------------------------------------

export const registry = rawRegistry as ContractRegistry

/**
* Returns a contract's ID by name, or throws if not found.
* @example getContractId('aid_escrow')
*/
export function getContractId(name: keyof typeof rawRegistry.contracts): string {
const entry = registry.contracts[name]
if (!entry) throw new Error(`[Soter Registry] Unknown contract: "${name}"`)
if (entry.contract_id.startsWith('REPLACE_WITH')) {
throw new Error(
`[Soter Registry] Contract "${name}" has not been deployed yet. ` +
`Run: ./contracts/registry/update-registry.sh`
)
}
return entry.contract_id
}

/**
* Returns a token's Stellar Asset Contract (SAC) ID by symbol.
* @example getTokenContractId('USDC')
*/
export function getTokenContractId(symbol: keyof typeof rawRegistry.tokens): string {
const token = registry.tokens[symbol]
if (!token) throw new Error(`[Soter Registry] Unknown token: "${symbol}"`)
return token.contract_id
}

export default registry
29 changes: 29 additions & 0 deletions app/onchain/contracts/registry/testnet.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# =============================================================================
# Soter — Testnet Contract Registry (env-style)
# Generated from: contracts/registry/testnet.registry.json
# Network: Stellar Testnet
# Network Passphrase: Test SDF Network ; September 2015
# =============================================================================
# HOW TO USE
# Source this file or copy individual variables into your .env:
# source contracts/registry/testnet.env
# Or reference in code:
# import registry from 'contracts/registry/testnet.registry.json'
# =============================================================================

# --- Network ---
NEXT_PUBLIC_STELLAR_NETWORK=testnet
NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org

# --- AidEscrow Contract ---
NEXT_PUBLIC_AID_ESCROW_CONTRACT_ID=REPLACE_WITH_CONTRACT_ID
AID_ESCROW_DEPLOYER_ADDRESS=REPLACE_WITH_DEPLOYER_PUBLIC_KEY
AID_ESCROW_WASM_HASH=REPLACE_WITH_WASM_HASH
AID_ESCROW_DEPLOYED_AT=REPLACE_WITH_ISO_TIMESTAMP
AID_ESCROW_DEPLOYED_AT_COMMIT=REPLACE_WITH_GIT_SHA

# --- Token Contracts (SAC) ---
NEXT_PUBLIC_USDC_CONTRACT_ID=CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC
NEXT_PUBLIC_XLM_CONTRACT_ID=CDMLFMKMMD7MWZP3FKUBZPVHTUEDLSX4BYGYKH4GCESXYHS3IHQ4EIG4
48 changes: 48 additions & 0 deletions app/onchain/contracts/registry/testnet.registry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"_meta": {
"description": "Soter Testnet Contract Registry — single source of truth for all deployed Soroban contract addresses, WASM hashes, and initialization configuration on Stellar Testnet.",
"network": "testnet",
"network_passphrase": "Test SDF Network ; September 2015",
"soroban_rpc_url": "https://soroban-testnet.stellar.org",
"horizon_url": "https://horizon-testnet.stellar.org",
"schema_version": "1.0.0",
"last_updated": "2025-01-15T00:00:00.000Z",
"deployed_at_commit": "REPLACE_WITH_GIT_SHA",
"maintainer": "Pulsefy/Soter"
},
"contracts": {
"aid_escrow": {
"contract_id": "REPLACE_WITH_CONTRACT_ID",
"deployer_address": "REPLACE_WITH_DEPLOYER_PUBLIC_KEY",
"wasm_hash": "REPLACE_WITH_WASM_HASH",
"deployed_at": "REPLACE_WITH_ISO_TIMESTAMP",
"deployed_at_commit": "REPLACE_WITH_GIT_SHA",
"init_args": {
"admin": "REPLACE_WITH_ADMIN_PUBLIC_KEY",
"token": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"fee_bps": 50,
"min_claim_amount": "1000000",
"max_claim_amount": "100000000000"
},
"description": "Core escrow contract handling creation, funding, and claiming of aid packages.",
"source": "app/contracts/src/aid_escrow.rs",
"abi_path": "contracts/registry/abi/aid_escrow.json"
}
},
"tokens": {
"USDC": {
"asset_code": "USDC",
"issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"decimals": 7,
"note": "Circle USDC on Stellar Testnet"
},
"XLM": {
"asset_code": "XLM",
"issuer": "native",
"contract_id": "CDMLFMKMMD7MWZP3FKUBZPVHTUEDLSX4BYGYKH4GCESXYHS3IHQ4EIG4",
"decimals": 7,
"note": "Native XLM wrapped as SAC on Testnet"
}
}
}
88 changes: 88 additions & 0 deletions app/onchain/contracts/registry/update-registry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# =============================================================================
# update-registry.sh
# Populates contracts/registry/testnet.registry.json with live values after
# a Soroban contract deployment on Stellar Testnet.
#
# Usage:
# ./contracts/registry/update-registry.sh \
# --contract-id <STELLAR_CONTRACT_ID> \
# --deployer <DEPLOYER_PUBLIC_KEY> \
# --wasm-hash <WASM_HASH> \
# --admin <ADMIN_PUBLIC_KEY>
#
# Requirements: jq, git
# =============================================================================

set -euo pipefail

REGISTRY_FILE="$(cd "$(dirname "$0")" && pwd)/testnet.registry.json"
ENV_FILE="$(cd "$(dirname "$0")" && pwd)/testnet.env"

# ---------- parse args -------------------------------------------------------
CONTRACT_ID=""
DEPLOYER=""
WASM_HASH=""
ADMIN=""

while [[ $# -gt 0 ]]; do
case $1 in
--contract-id) CONTRACT_ID="$2"; shift 2 ;;
--deployer) DEPLOYER="$2"; shift 2 ;;
--wasm-hash) WASM_HASH="$2"; shift 2 ;;
--admin) ADMIN="$2"; shift 2 ;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
done

if [[ -z "$CONTRACT_ID" || -z "$DEPLOYER" || -z "$WASM_HASH" || -z "$ADMIN" ]]; then
echo "Error: --contract-id, --deployer, --wasm-hash, and --admin are all required."
exit 1
fi

# ---------- capture context --------------------------------------------------
GIT_SHA=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")

echo "Updating registry..."
echo " contract_id : $CONTRACT_ID"
echo " deployer : $DEPLOYER"
echo " wasm_hash : $WASM_HASH"
echo " admin : $ADMIN"
echo " git_sha : $GIT_SHA"
echo " timestamp : $TIMESTAMP"

# ---------- patch JSON -------------------------------------------------------
jq \
--arg contract_id "$CONTRACT_ID" \
--arg deployer "$DEPLOYER" \
--arg wasm_hash "$WASM_HASH" \
--arg admin "$ADMIN" \
--arg git_sha "$GIT_SHA" \
--arg timestamp "$TIMESTAMP" \
'
._meta.last_updated = $timestamp |
._meta.deployed_at_commit = $git_sha |
.contracts.aid_escrow.contract_id = $contract_id |
.contracts.aid_escrow.deployer_address = $deployer |
.contracts.aid_escrow.wasm_hash = $wasm_hash |
.contracts.aid_escrow.deployed_at = $timestamp |
.contracts.aid_escrow.deployed_at_commit = $git_sha |
.contracts.aid_escrow.init_args.admin = $admin
' \
"$REGISTRY_FILE" > "${REGISTRY_FILE}.tmp" && mv "${REGISTRY_FILE}.tmp" "$REGISTRY_FILE"

# ---------- sync env file ----------------------------------------------------
sed -i \
-e "s|REPLACE_WITH_CONTRACT_ID|$CONTRACT_ID|g" \
-e "s|REPLACE_WITH_DEPLOYER_PUBLIC_KEY|$DEPLOYER|g" \
-e "s|REPLACE_WITH_WASM_HASH|$WASM_HASH|g" \
-e "s|REPLACE_WITH_ISO_TIMESTAMP|$TIMESTAMP|g" \
-e "s|REPLACE_WITH_GIT_SHA|$GIT_SHA|g" \
-e "s|REPLACE_WITH_ADMIN_PUBLIC_KEY|$ADMIN|g" \
"$ENV_FILE"

echo ""
echo "Registry updated successfully:"
echo " $REGISTRY_FILE"
echo " $ENV_FILE"
Loading