Store the verification key, Issuer public key, admin, USDC token, and fee. Called once after a fresh deploy.
fee_amount — issuance fee in USDC units (7 decimals).
0 = free (recommended for launch). 20_000_000 = 2.00 USDC.
Adjustable post-deploy via set_fee() without redeploying.
fn initialize(
env: soroban_sdk::Env,
vk: StoredVk,
issuer_pub_key: soroban_sdk::BytesN<32>,
admin: soroban_sdk::Address,
treasury: soroban_sdk::Address,
usdc_token: soroban_sdk::Address,
fee_amount: i128,
) -> Result<(), AgeVerifierError>
Set admin, USDC token, and fee on an already-initialized contract. Used after a WASM upgrade when the old contract had no fee config. Fails if Admin is already set (one-shot migration only).
fn configure_fees(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
treasury: soroban_sdk::Address,
usdc_token: soroban_sdk::Address,
fee_amount: i128,
) -> Result<(), AgeVerifierError>
Verify a Groth16 proof, collect the USDC issuance fee, and mint a soulbound credential.
caller — address paying the fee and receiving the credential.
Must match the Stellar address used to derive pub_inputs[2].
pub_inputs — [isOldEnough: Fr(1), commitment: Fr, addressHash: Fr]
nullifier — unique 32-byte anti-replay token (random, client-side).
issuer_sig — Ed25519 signature (64 bytes) from the trusted Issuer over commitment bytes.
fn verify(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
proof: Groth16Proof,
pub_inputs: soroban_sdk::Vec,
nullifier: soroban_sdk::BytesN<32>,
issuer_sig: soroban_sdk::BytesN<64>,
) -> Result
Check whether an address hash already has a verified credential.
fn has_credential(env: soroban_sdk::Env, address_hash: soroban_sdk::BytesN<32>) -> bool
Check credential by Stellar Address — used by soulbound_nft via cross-contract call. Avoids requiring callers to recompute the BN254 field element from the address.
fn has_credential_by_address(env: soroban_sdk::Env, addr: soroban_sdk::Address) -> bool
Check whether a nullifier has been consumed.
fn is_nullifier_used(env: soroban_sdk::Env, nullifier: soroban_sdk::BytesN<32>) -> bool
Return the current issuance fee in USDC units (7 decimals). 0 = free.
fn get_fee(env: soroban_sdk::Env) -> i128
Return the current treasury address.
fn get_treasury(env: soroban_sdk::Env) -> Option
Admin — rotate the treasury address. Affects only future fee collections; funds already at the old treasury address are unaffected. Does not require a timelock — no funds move, only the destination changes.
fn set_treasury(
env: soroban_sdk::Env,
new_treasury: soroban_sdk::Address,
) -> Result<(), AgeVerifierError>
Admin — update the issuance fee without redeploying. fee_amount in USDC units (7 decimals): 20_000_000 = 2.00 USDC. 0 = free. Maximum fee: 100_000_000 (10.00 USDC) — enforced to prevent fee-based DoS.
fn set_fee(env: soroban_sdk::Env, fee_amount: i128) -> Result<(), AgeVerifierError>
Admin — initiate a withdrawal. Funds are locked for 48h before execution.
Security model: if the admin key is compromised, this 48h window gives the
team time to detect the attack and rotate the key (via Stellar account management)
before execute_withdraw() can be called with the old compromised key.
Recommended: configure the admin Stellar account as a 2-of-3 multisig so that a single compromised key cannot even reach this call unilaterally.
fn request_withdraw(
env: soroban_sdk::Env,
to: soroban_sdk::Address,
amount: i128,
) -> Result<(), AgeVerifierError>
Admin — execute a previously requested withdrawal after the 48h timelock has expired. Requires the current admin key — a rotated key blocks a compromised key from executing.
fn execute_withdraw(env: soroban_sdk::Env) -> Result<(), AgeVerifierError>
Admin — cancel a pending withdrawal request before the timelock expires. Call this immediately after detecting a compromise to neutralize the attack.
fn cancel_withdraw(env: soroban_sdk::Env) -> Result<(), AgeVerifierError>
Return the pending withdrawal request, if any.
fn get_pending_withdrawal(env: soroban_sdk::Env) -> Option
Admin — upgrade the contract WASM. Contract ID stays the same; all storage is preserved.
fn upgrade(
env: soroban_sdk::Env,
new_wasm_hash: soroban_sdk::BytesN<32>,
) -> Result<(), AgeVerifierError>