2020-10-27 02:43:05 +01:00
|
|
|
request_funds(1){
|
2020-10-27 00:29:41 +01:00
|
|
|
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}}
|
2020-10-27 02:59:35 +01:00
|
|
|
},
|
|
|
|
"require_coin":true
|
2020-10-27 00:29:41 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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}};
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// 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).
|
2020-10-27 00:29:41 +01:00
|
|
|
reserved_amount = "2400";
|
|
|
|
sender = find_balance({
|
|
|
|
"minimum_balance":{
|
|
|
|
"value": {{reserved_amount}},
|
|
|
|
"currency": {{currency}}
|
|
|
|
},
|
|
|
|
"require_coin": true
|
|
|
|
});
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// 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}};
|
2020-10-27 00:29:41 +01:00
|
|
|
recipient_amount = random_number({
|
|
|
|
"minimum": {{dust_amount}},
|
2020-10-27 16:31:48 +01:00
|
|
|
"maximum": {{receivable_amount}}
|
2020-10-27 00:29:41 +01:00
|
|
|
});
|
|
|
|
print_message({
|
|
|
|
"recipient_amount":{{recipient_amount}}
|
|
|
|
});
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// 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}};
|
2020-10-27 00:29:41 +01:00
|
|
|
print_message({
|
|
|
|
"change_amount":{{change_amount}}
|
|
|
|
});
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// 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.
|
2020-10-27 01:14:16 +01:00
|
|
|
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
|
|
|
|
});
|
2020-10-27 16:31:48 +01:00
|
|
|
|
|
|
|
sender_amount = 0 - {{sender.balance.value}};
|
2020-10-27 01:14:16 +01:00
|
|
|
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{
|
2020-10-27 16:31:48 +01:00
|
|
|
// The suggested_fee is returned in the /construction/metadata
|
|
|
|
// response and saved to transfer_dry_run.suggested_fee.
|
2020-10-27 01:14:16 +01:00
|
|
|
suggested_fee = find_currency_amount({
|
|
|
|
"currency":{{currency}},
|
|
|
|
"amounts":{{transfer_dry_run.suggested_fee}}
|
|
|
|
});
|
2020-10-27 16:31:48 +01:00
|
|
|
|
|
|
|
// 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}};
|
2020-10-27 01:14:16 +01:00
|
|
|
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}}}
|
|
|
|
}
|
|
|
|
];
|
2020-10-27 02:43:05 +01:00
|
|
|
}
|
2020-10-27 01:14:16 +01:00
|
|
|
}
|
2020-10-27 00:29:41 +01:00
|
|
|
|
2020-10-27 01:14:16 +01:00
|
|
|
return_funds(10){
|
|
|
|
transfer_dry_run{
|
|
|
|
transfer_dry_run.network = {"network":"Testnet3", "blockchain":"Bitcoin"};
|
|
|
|
currency = {"symbol":"tBTC", "decimals":8};
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// 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).
|
2020-10-27 01:14:16 +01:00
|
|
|
max_fee_amount = "1200";
|
|
|
|
reserved_amount = "1800";
|
|
|
|
sender = find_balance({
|
|
|
|
"minimum_balance":{
|
|
|
|
"value": {{reserved_amount}},
|
|
|
|
"currency": {{currency}}
|
|
|
|
},
|
|
|
|
"require_coin": true
|
|
|
|
});
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// 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.
|
2020-10-27 01:14:16 +01:00
|
|
|
recipient_amount = {{sender.balance.value}} - {{max_fee_amount}};
|
|
|
|
print_message({
|
|
|
|
"recipient_amount":{{recipient_amount}}
|
|
|
|
});
|
|
|
|
|
2020-10-27 16:31:48 +01:00
|
|
|
// We load the recipient address from an ENV.
|
|
|
|
recipient_address = load_env("RECIPIENT");
|
|
|
|
recipient = {"address": {{recipient_address}}};
|
|
|
|
|
2020-10-27 01:14:16 +01:00
|
|
|
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}}}
|
|
|
|
}
|
|
|
|
];
|
2020-10-27 00:29:41 +01:00
|
|
|
},
|
|
|
|
transfer{
|
2020-10-27 16:31:48 +01:00
|
|
|
// The suggested_fee is returned in the /construction/metadata
|
|
|
|
// response and saved to transfer_dry_run.suggested_fee.
|
2020-10-27 01:14:16 +01:00
|
|
|
suggested_fee = find_currency_amount({
|
|
|
|
"currency":{{currency}},
|
|
|
|
"amounts":{{transfer_dry_run.suggested_fee}}
|
|
|
|
});
|
2020-10-27 16:31:48 +01:00
|
|
|
|
|
|
|
// We calculate the recipient_amount using the new suggested_fee
|
|
|
|
// and assert that it is above the minimum UTXO size.
|
2020-10-27 01:14:16 +01:00
|
|
|
recipient_amount = {{sender.balance.value}} - {{suggested_fee.value}};
|
|
|
|
dust_amount = "600";
|
|
|
|
recipient_minus_dust = {{recipient_amount}} - {{dust_amount}};
|
|
|
|
assert({{recipient_minus_dust}});
|
2020-10-27 16:31:48 +01:00
|
|
|
|
2020-10-27 01:14:16 +01:00
|
|
|
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}}}
|
|
|
|
}
|
|
|
|
];
|
2020-10-27 02:43:05 +01:00
|
|
|
}
|
2020-10-27 00:29:41 +01:00
|
|
|
}
|