request_funds(1){ find_account{ currency = {"symbol":"tBTC", "decimals":8}; random_account = find_balance({ "minimum_balance":{ "value": "0", "currency": {{currency}} }, "create_limit":1 }); }, // Create a separate scenario to request funds so that // the address we are using to request funds does not // get rolled back if funds do not yet exist. request{ loaded_account = find_balance({ "account_identifier": {{random_account.account_identifier}}, "minimum_balance":{ "value": "1000000", "currency": {{currency}} }, "require_coin":true }); } } create_account(1){ create{ network = {"network":"Testnet3", "blockchain":"Bitcoin"}; key = generate_key({"curve_type": "secp256k1"}); account = derive({ "network_identifier": {{network}}, "public_key": {{key.public_key}} }); // If the account is not saved, the key will be lost! save_account({ "account_identifier": {{account.account_identifier}}, "keypair": {{key}} }); } } transfer(10){ transfer_dry_run{ transfer_dry_run.network = {"network":"Testnet3", "blockchain":"Bitcoin"}; currency = {"symbol":"tBTC", "decimals":8}; // We set the max_fee_amount to know how much buffer we should // leave for fee payment when selecting a sender account. dust_amount = "600"; max_fee_amount = "1200"; send_buffer = {{dust_amount}} + {{max_fee_amount}}; // We look for a coin of value >= the reserved_amount to create // a transfer with change (reserved_amount is max_fee_amount + dust_amount x 2). reserved_amount = "2400"; sender = find_balance({ "minimum_balance":{ "value": {{reserved_amount}}, "currency": {{currency}} }, "require_coin": true }); // The amount we send to the recipient is a random value // between the dust_amount and the value of the entire coin (minus // the amount reserved for fee payment and covering the dust minimum // of the change UTXO). receivable_amount = {{sender.balance.value}} - {{send_buffer}}; recipient_amount = random_number({ "minimum": {{dust_amount}}, "maximum": {{receivable_amount}} }); print_message({ "recipient_amount":{{recipient_amount}} }); // The change amount is what we aren't sending to the recipient // minus the maximum fee. Don't worry, we will adjust this // amount to avoid overpaying the fee after the dry run // completes. raw_change_amount = {{sender.balance.value}} - {{recipient_amount}}; change_amount = {{raw_change_amount}} - {{max_fee_amount}}; print_message({ "change_amount":{{change_amount}} }); // The last thing we need to do before creating the transaction // is to find a recipient with a *types.AccountIdentifier that // is not equal to the sender. recipient = find_balance({ "not_account_identifier":[{{sender.account_identifier}}], "not_coins":[{{sender.coin}}], "minimum_balance":{ "value": "0", "currency": {{currency}} }, "create_limit": 100, "create_probability": 50 }); sender_amount = 0 - {{sender.balance.value}}; transfer_dry_run.confirmation_depth = "1"; transfer_dry_run.dry_run = true; transfer_dry_run.operations = [ { "operation_identifier":{"index":0}, "type":"INPUT", "account":{{sender.account_identifier}}, "amount":{"value":{{sender_amount}},"currency":{{currency}}}, "coin_change":{"coin_action":"coin_spent", "coin_identifier":{{sender.coin}}} }, { "operation_identifier":{"index":1}, "type":"OUTPUT", "account":{{recipient.account_identifier}}, "amount":{"value":{{recipient_amount}},"currency":{{currency}}} }, { "operation_identifier":{"index":2}, "type":"OUTPUT", "account":{{sender.account_identifier}}, "amount":{"value":{{change_amount}},"currency":{{currency}}} } ]; }, transfer{ // The suggested_fee is returned in the /construction/metadata // response and saved to transfer_dry_run.suggested_fee. suggested_fee = find_currency_amount({ "currency":{{currency}}, "amounts":{{transfer_dry_run.suggested_fee}} }); // We can access the variables of other scenarios, so we don't // need to recalculate raw_change_amount. change_amount = {{raw_change_amount}} - {{suggested_fee.value}}; transfer.network = {{transfer_dry_run.network}}; transfer.confirmation_depth = {{transfer_dry_run.confirmation_depth}}; transfer.operations = [ { "operation_identifier":{"index":0}, "type":"INPUT", "account":{{sender.account_identifier}}, "amount":{"value":{{sender_amount}},"currency":{{currency}}}, "coin_change":{"coin_action":"coin_spent", "coin_identifier":{{sender.coin}}} }, { "operation_identifier":{"index":1}, "type":"OUTPUT", "account":{{recipient.account_identifier}}, "amount":{"value":{{recipient_amount}},"currency":{{currency}}} }, { "operation_identifier":{"index":2}, "type":"OUTPUT", "account":{{sender.account_identifier}}, "amount":{"value":{{change_amount}},"currency":{{currency}}} } ]; } } return_funds(10){ transfer_dry_run{ transfer_dry_run.network = {"network":"Testnet3", "blockchain":"Bitcoin"}; currency = {"symbol":"tBTC", "decimals":8}; // We look for a sender that is able to pay the // max_fee_amount + min_utxo size (reserved_amount is max_fee_amount + min_utxo size). max_fee_amount = "1200"; reserved_amount = "1800"; sender = find_balance({ "minimum_balance":{ "value": {{reserved_amount}}, "currency": {{currency}} }, "require_coin": true }); // We send the maximum amount available to the recipient. Don't worry // we will modify this after the dry run to make sure we don't overpay. recipient_amount = {{sender.balance.value}} - {{max_fee_amount}}; print_message({ "recipient_amount":{{recipient_amount}} }); // We load the recipient address from an ENV. recipient_address = load_env("RECIPIENT"); recipient = {"address": {{recipient_address}}}; sender_amount = 0 - {{sender.balance.value}}; transfer_dry_run.confirmation_depth = "1"; transfer_dry_run.dry_run = true; transfer_dry_run.operations = [ { "operation_identifier":{"index":0}, "type":"INPUT", "account":{{sender.account_identifier}}, "amount":{"value":{{sender_amount}},"currency":{{currency}}}, "coin_change":{"coin_action":"coin_spent", "coin_identifier":{{sender.coin}}} }, { "operation_identifier":{"index":1}, "type":"OUTPUT", "account":{{recipient}}, "amount":{"value":{{recipient_amount}},"currency":{{currency}}} } ]; }, transfer{ // The suggested_fee is returned in the /construction/metadata // response and saved to transfer_dry_run.suggested_fee. suggested_fee = find_currency_amount({ "currency":{{currency}}, "amounts":{{transfer_dry_run.suggested_fee}} }); // We calculate the recipient_amount using the new suggested_fee // and assert that it is above the minimum UTXO size. recipient_amount = {{sender.balance.value}} - {{suggested_fee.value}}; dust_amount = "600"; recipient_minus_dust = {{recipient_amount}} - {{dust_amount}}; assert({{recipient_minus_dust}}); transfer.network = {{transfer_dry_run.network}}; transfer.confirmation_depth = {{transfer_dry_run.confirmation_depth}}; transfer.operations = [ { "operation_identifier":{"index":0}, "type":"INPUT", "account":{{sender.account_identifier}}, "amount":{"value":{{sender_amount}},"currency":{{currency}}}, "coin_change":{"coin_action":"coin_spent", "coin_identifier":{{sender.coin}}} }, { "operation_identifier":{"index":1}, "type":"OUTPUT", "account":{{recipient}}, "amount":{"value":{{recipient_amount}},"currency":{{currency}}} } ]; } }