Skip to content

Add admin gold trustline initialization for XAUT - #17

Closed
sudo-robi wants to merge 2 commits into
DXmakers:mainfrom
sudo-robi:issue-3.1-define-gold-asset-trustlines
Closed

Add admin gold trustline initialization for XAUT#17
sudo-robi wants to merge 2 commits into
DXmakers:mainfrom
sudo-robi:issue-3.1-define-gold-asset-trustlines

Conversation

@sudo-robi

Copy link
Copy Markdown
Contributor

closes #9

This PR introduces contract initialization with an admin account, then adds a dedicated function to initialize Gold trustline metadata using the canonical asset configured as XAUT with issuer GCRLXTLD7XIRXWXV2PDCC74O5TUUKN3OODJAM6TWVE4AIRNMGQJK3KWQ. The trustline setup function requires admin authorization and enforces a minimum base reserve of 5,000,000 stroops before marking the trustline as ready.

Changes included:

Added initialize(env, admin) to set contract admin once
Added init_gold_trustline(env, admin, reserve_stroops) with:
admin-only access
base reserve validation
persistent storage of Gold asset code, issuer, reserve amount, and ready flag
Added read helpers:
get_gold_asset()
is_gold_trustline_ready()
get_gold_reserve_stroops()
Added/updated tests to validate the full initialization flow and existing deposit/withdraw behavior
Validation:

cargo test passes (2 passed, 0 failed)
Acceptance criteria coverage:

Contract is authorized through explicit admin-gated Gold trustline initialization state
Submitting the initialization transaction creates/updates persistent ledger entries for Gold trustline state and reserve tracking

Copilot AI review requested due to automatic review settings March 26, 2026 10:49
@drips-wave

drips-wave Bot commented Mar 26, 2026

Copy link
Copy Markdown

@sudo-robi Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an admin initialization flow to the Soroban contract and introduces “Gold (XAUT)” configuration state intended to represent trustline readiness, along with tests and updated test snapshot output.

Changes:

  • Added initialize(env, admin) to persist a one-time contract admin.
  • Added init_gold_trustline(...) plus read helpers to persist canonical XAUT metadata, a reserve value, and a readiness flag.
  • Updated tests (and golden snapshot) to include the new initialization/auth flow.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
contracts/src/lib.rs Adds admin init, gold “trustline” state, read helpers, and new/updated tests.
contracts/test_snapshots/test/test_deposit_withdraw.1.json Updates snapshot to reflect added initialize auth and new persistent Admin entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread contracts/src/lib.rs
.storage()
.persistent()
.get(&DataKey::GoldAssetIssuer)
.unwrap_or(String::from_str(&env, CANONICAL_GOLD_ASSET_ISSUER));

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_gold_asset uses unwrap_or(String::from_str(...)), which eagerly allocates the default issuer string even when the value is present in storage. On Soroban this adds unnecessary host work/fees on every call; use a lazy fallback (e.g., unwrap_or_else) so the String is only constructed when the key is missing.

Suggested change
.unwrap_or(String::from_str(&env, CANONICAL_GOLD_ASSET_ISSUER));
.unwrap_or_else(|| String::from_str(&env, CANONICAL_GOLD_ASSET_ISSUER));

Copilot uses AI. Check for mistakes.
Comment thread contracts/src/lib.rs
Comment on lines +36 to +63
pub fn init_gold_trustline(env: Env, admin: Address, reserve_stroops: i128) {
let stored_admin: Address = env
.storage()
.persistent()
.get(&DataKey::Admin)
.expect("Contract not initialized");

assert!(admin == stored_admin, "Only admin can initialize Gold trustline");
admin.require_auth();
assert!(
reserve_stroops >= TRUSTLINE_BASE_RESERVE_STROOPS,
"Insufficient base reserve for trustline"
);

let gold_issuer = String::from_str(&env, CANONICAL_GOLD_ASSET_ISSUER);
env.storage()
.persistent()
.set(&DataKey::GoldAssetCode, &CANONICAL_GOLD_ASSET_CODE);
env.storage()
.persistent()
.set(&DataKey::GoldAssetIssuer, &gold_issuer);
env.storage()
.persistent()
.set(&DataKey::GoldTrustlineReserveStroops, &reserve_stroops);
env.storage()
.persistent()
.set(&DataKey::GoldTrustlineReady, &true);
}

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init_gold_trustline currently only writes metadata/flags to contract storage and does not establish any on-ledger trustline or interact with an asset/token contract. If the intent is to actually authorize/enable holding XAUT, this function needs to call the relevant Stellar asset/token contract APIs; otherwise, consider renaming/rewording to reflect that it only configures the canonical Gold asset and marks it "ready" in contract state.

Copilot uses AI. Check for mistakes.
Comment thread contracts/src/lib.rs
Comment on lines +28 to +62
pub fn initialize(env: Env, admin: Address) {
if env.storage().persistent().has(&DataKey::Admin) {
panic!("Already initialized");
}
admin.require_auth();
env.storage().persistent().set(&DataKey::Admin, &admin);
}

pub fn init_gold_trustline(env: Env, admin: Address, reserve_stroops: i128) {
let stored_admin: Address = env
.storage()
.persistent()
.get(&DataKey::Admin)
.expect("Contract not initialized");

assert!(admin == stored_admin, "Only admin can initialize Gold trustline");
admin.require_auth();
assert!(
reserve_stroops >= TRUSTLINE_BASE_RESERVE_STROOPS,
"Insufficient base reserve for trustline"
);

let gold_issuer = String::from_str(&env, CANONICAL_GOLD_ASSET_ISSUER);
env.storage()
.persistent()
.set(&DataKey::GoldAssetCode, &CANONICAL_GOLD_ASSET_CODE);
env.storage()
.persistent()
.set(&DataKey::GoldAssetIssuer, &gold_issuer);
env.storage()
.persistent()
.set(&DataKey::GoldTrustlineReserveStroops, &reserve_stroops);
env.storage()
.persistent()
.set(&DataKey::GoldTrustlineReady, &true);

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admin/Gold configuration is stored as persistent entries but their TTL is never extended. On Soroban, persistent entries can expire if not bumped, which would effectively “lose” admin/gold readiness over time. If these values are meant to be permanent configuration, explicitly extend the TTL for the keys when setting/reading them (or have a periodic maintenance/refresh strategy).

Copilot uses AI. Check for mistakes.
Comment thread contracts/src/lib.rs
Comment on lines +128 to +149
#[test]
fn test_initialize_gold_trustline() {
let env = Env::default();
let contract_id = env.register_contract(None, SmasageYieldRouter);
let client = SmasageYieldRouterClient::new(&env, &contract_id);

let admin = Address::generate(&env);

env.mock_all_auths();

client.initialize(&admin);
client.init_gold_trustline(&admin, &5_000_000);

let (asset_code, asset_issuer) = client.get_gold_asset();
assert_eq!(asset_code, symbol_short!("XAUT"));
assert_eq!(
asset_issuer,
String::from_str(&env, "GCRLXTLD7XIRXWXV2PDCC74O5TUUKN3OODJAM6TWVE4AIRNMGQJK3KWQ")
);
assert!(client.is_gold_trustline_ready());
assert_eq!(client.get_gold_reserve_stroops(), 5_000_000);
}

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new initialization/admin gating logic is only covered by a happy-path test. Add negative tests for at least: calling init_gold_trustline before initialize, calling it with a non-admin address, passing reserve_stroops below the minimum, and double-calling initialize (should fail). This helps ensure the access control and validation can’t regress.

Copilot uses AI. Check for mistakes.
Comment thread contracts/src/lib.rs
Comment on lines +45 to +48
assert!(
reserve_stroops >= TRUSTLINE_BASE_RESERVE_STROOPS,
"Insufficient base reserve for trustline"
);

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reserve_stroops validation is currently against a hard-coded constant and the value itself is entirely caller-provided, so it doesn’t prove that any real on-ledger reserve has been funded/covered (and the network base reserve can change over time). If the goal is to validate against the network’s current base reserve, consider deriving the required minimum from ledger parameters; otherwise, consider renaming/clarifying this field as an informational “declared reserve” rather than an enforced guarantee.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue 3.1: Define Gold Asset Trustlines

3 participants