What problem does your feature solve?
Working with native tokens (XLM) in unit tests is unnecessarily complicated, and CAP-73 now lets contracts create G-accounts, but testing that flow requires funding those accounts with native tokens, something the SDK doesn't directly support.
There are two specific gaps.
1. No straightforward way to obtain the native SAC.
I work around it like this:
fn register_native_sac(env: &Env) -> Address {
let asset = Bytes::from_slice(env, &[0, 0, 0, 0]);
env.deployer().with_stellar_asset(asset).deploy()
}
@aolieman uses a similar approach.
But even once you have the SAC, there's no way to mint into it.
2. No way to fund G-accounts.
For C-addresses, Address::generate() from testutils works fine. For G-accounts, the only path I've found is to manually construct a ledger entry and inject it via the host:
fn generate_funded_g_account(env: &Env, stroops: i64) -> Address {
let pk: [u8; 32] = BytesN::<32>::random(env).to_array();
let account_id = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(pk)));
let key = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount {
account_id: account_id.clone(),
}));
let entry = Rc::new(xdr::LedgerEntry {
data: xdr::LedgerEntryData::Account(xdr::AccountEntry {
account_id: account_id.clone(),
balance: stroops,
flags: 0,
home_domain: Default::default(),
inflation_dest: None,
num_sub_entries: 0,
seq_num: xdr::SequenceNumber(0),
thresholds: xdr::Thresholds([1; 4]),
signers: xdr::VecM::default(),
ext: xdr::AccountEntryExt::V0,
}),
last_modified_ledger_seq: 0,
ext: xdr::LedgerEntryExt::V0,
});
env.host().add_ledger_entry(&key, &entry, None).unwrap();
Address::try_from_val(env, &xdr::ScAddress::Account(account_id)).unwrap()
}
This depends on internal host APIs and a lot of XDR boilerplate. Again, @aolieman has similar workaround code.
Multiple users converging on the same hacks suggests this belongs in testutils.
What would you like to see?
Two additions to testutils:
- A helper to obtain the native SAC, e.g.
env.native_asset_contract() or an equivalent on Env/StellarAssetContract.
- A way to mint native tokens in tests, either by exposing admin capabilities on the native SAC, or via a dedicated
env.fund_account(address, stroops) helper that works for both G- and C-addresses.
Together these would make CAP-73 end-to-end testable: contracts that create and fund G-accounts could be exercised in unit tests without resorting to host-level ledger entry injection.
As a related note (probably worth a separate issue): distinguishing C-addresses from G-addresses given an Address is also harder than it should be (both in test and also in contract code). A built-in way to check the address type would pair well with the helpers above.
What problem does your feature solve?
Working with native tokens (XLM) in unit tests is unnecessarily complicated, and CAP-73 now lets contracts create G-accounts, but testing that flow requires funding those accounts with native tokens, something the SDK doesn't directly support.
There are two specific gaps.
1. No straightforward way to obtain the native SAC.
I work around it like this:
@aolieman uses a similar approach.
But even once you have the SAC, there's no way to mint into it.
2. No way to fund G-accounts.
For C-addresses,
Address::generate()fromtestutilsworks fine. For G-accounts, the only path I've found is to manually construct a ledger entry and inject it via the host:This depends on internal host APIs and a lot of XDR boilerplate. Again, @aolieman has similar workaround code.
Multiple users converging on the same hacks suggests this belongs in
testutils.What would you like to see?
Two additions to
testutils:env.native_asset_contract()or an equivalent onEnv/StellarAssetContract.env.fund_account(address, stroops)helper that works for both G- and C-addresses.Together these would make CAP-73 end-to-end testable: contracts that create and fund G-accounts could be exercised in unit tests without resorting to host-level ledger entry injection.
As a related note (probably worth a separate issue): distinguishing C-addresses from G-addresses given an Address is also harder than it should be (both in test and also in contract code). A built-in way to check the address type would pair well with the helpers above.