-
Notifications
You must be signed in to change notification settings - Fork 2
Description
I'm working on sorocarbon, which relies heavily on SAC calls. Since the SAC is implemented as a built-in (i.e. host) contract, there is no WASM binary available for me to test with.
This puts me in a bind, since the contract logic that is worth verifying uses SAC calls. There's no way around that. It depends on mint and set_authorized, which are not available in the TokenInterface. I think the problem can be solved by creating a realistic implementation of the SAC as a normal Soroban contract. There is likely a starting point available, see this discord thread for up-to-date info.
Would you consider incorporating a drop-in replacement for the SAC in komet? There shouldn't be anything special to support, unless you'd like to include cheat functions to manipulate classic ledger entries. The experience could just be a bit nicer if the SAC WASM is published here.
To illustrate, here's my test that also requires SAC calls, for setup and assertions:
pub fn test_swap_is_atomic(
env: Env,
funder: Address,
recipient: Address,
amount: i64,
project_id: Symbol,
) -> bool {
// bail if `amount` is not valid for mint
// TODO: check on `assume` status in komet#74
if 1 > amount {
return true;
}
// create SAC token clients
let carbon_addr = env.storage().instance().get(&DataKey::CarbonID).expect(
"CARBON SAC address must be set."
);
let csink_addr = env.storage().instance().get(&DataKey::CarbonSinkID).expect(
"CarbonSINK SAC address must be set."
);
let carbon_token_client = TokenClient::new(&env, &carbon_addr);
let csink_token_client = TokenClient::new(&env, &csink_addr);
// credit the funder with exactly `amount` of CARBON
let carbon_sac_client = StellarAssetClient::new(&env, &csink_addr);
carbon_sac_client.mint(&funder, &amount.into());
// create the SinkContract client
let sink_addr: Address = env.storage().instance().get(&DataKey::SinkID).unwrap();
let sink_client = sink_contract::Client::new(&env, &sink_addr);
// collect balances before the swap
let contract_carbon_before = carbon_token_client.balance(&sink_addr);
let contract_csink_before = csink_token_client.balance(&sink_addr);
let funder_carbon_before = carbon_token_client.balance(&funder);
let funder_csink_before = csink_token_client.balance(&funder);
let recipient_carbon_before = carbon_token_client.balance(&recipient);
let recipient_csink_before = csink_token_client.balance(&recipient);
// Call the `sink_carbon` method of the sink contract
// it makes several internal SAC calls
let empty_string = String::from_str(&env, "");
let sink_res = sink_client.try_sink_carbon(
&funder, &recipient, &amount, &project_id, &empty_string, &empty_string
);
// TODO: check for SinkError::AmountTooLow
// collect balances after the swap
let contract_carbon_after = carbon_token_client.balance(&sink_addr);
let contract_csink_after = csink_token_client.balance(&sink_addr);
let funder_carbon_after = carbon_token_client.balance(&funder);
let funder_csink_after = csink_token_client.balance(&funder);
let recipient_carbon_after = carbon_token_client.balance(&recipient);
let recipient_csink_after = csink_token_client.balance(&recipient);
// assert all contract balances are empty
let contract_balances = [
contract_carbon_before, contract_csink_before,
contract_carbon_after, contract_csink_after
];
let max_balance = contract_balances.iter().max().unwrap();
if *max_balance > 0 { return false; }
// assert the effect on funder balances
if funder_carbon_before != amount as i128 { return false; }
if funder_carbon_after >= 10_000 { return false; }
if funder_csink_before != 0 { return false; }
if funder_csink_after != 0 { return false; }
// assert the effect on recipient balances
if recipient_carbon_before != 0 { return false; }
if recipient_carbon_after != 0 { return false; }
if recipient_csink_before != 0 { return false; }
let quantization_remainder = amount as i128 - recipient_csink_after;
if quantization_remainder >= 10_000 { return false; }
// assert quantization remainders are equal
funder_carbon_after == quantization_remainder
}