diff --git a/src/extrinsic/balances.rs b/src/extrinsic/balances.rs
index 709a9d816..ebb4a2c57 100644
--- a/src/extrinsic/balances.rs
+++ b/src/extrinsic/balances.rs
@@ -30,11 +30,15 @@ use codec::{Compact, Encode};
pub const BALANCES_MODULE: &str = "Balances";
pub const TRANSFER_ALLOW_DEATH: &str = "transfer_allow_death";
+pub const TRANSFER_KEEP_ALIVE: &str = "transfer_keep_alive";
pub const FORCE_SET_BALANCE: &str = "force_set_balance";
/// Call for a balance transfer.
pub type TransferAllowDeathCall
= (CallIndex, Address, Compact);
+/// Call for a balance transfer.
+pub type TransferKeepAliveCall = (CallIndex, Address, Compact);
+
/// Call to the balance of an account.
pub type ForceSetBalanceCall = (CallIndex, Address, Compact);
@@ -52,6 +56,14 @@ pub trait BalancesExtrinsics {
amount: Self::Balance,
) -> Option>>;
+ /// Transfer some liquid free balance to another account.
+ #[allow(clippy::type_complexity)]
+ async fn balance_transfer_keep_alive(
+ &self,
+ to: Self::Address,
+ amount: Self::Balance,
+ ) -> Option>>;
+
/// Set the balances of a given account.
#[allow(clippy::type_complexity)]
async fn balance_force_set_balance(
@@ -85,6 +97,15 @@ where
compose_extrinsic!(self, BALANCES_MODULE, TRANSFER_ALLOW_DEATH, to, Compact(amount))
}
+ #[allow(clippy::type_complexity)]
+ async fn balance_transfer_keep_alive(
+ &self,
+ to: Self::Address,
+ amount: Self::Balance,
+ ) -> Option>> {
+ compose_extrinsic!(self, BALANCES_MODULE, TRANSFER_KEEP_ALIVE, to, Compact(amount))
+ }
+
async fn balance_force_set_balance(
&self,
who: Self::Address,
diff --git a/testing/async/examples/dispatch_errors_tests.rs b/testing/async/examples/dispatch_errors_tests.rs
index 0ebc516b7..aa740d924 100644
--- a/testing/async/examples/dispatch_errors_tests.rs
+++ b/testing/async/examples/dispatch_errors_tests.rs
@@ -20,7 +20,7 @@ use sp_keyring::AccountKeyring;
use sp_runtime::MultiAddress;
use substrate_api_client::{
ac_primitives::AssetRuntimeConfig, extrinsic::BalancesExtrinsics, rpc::JsonrpseeClient, Api,
- Error, GetAccountInformation, SubmitAndWatch, XtStatus,
+ Error, GetAccountInformation, GetBalance, SubmitAndWatch, XtStatus,
};
#[tokio::main]
@@ -33,7 +33,7 @@ async fn main() {
let alice = AccountKeyring::Alice.to_account_id();
let balance_of_alice = api.get_account_data(&alice).await.unwrap().unwrap().free;
- println!("[+] Alice's Free Balance is is {}\n", balance_of_alice);
+ println!("[+] Alice's Free Balance is {}\n", balance_of_alice);
let bob = AccountKeyring::Bob.to_account_id();
let balance_of_bob = api.get_account_data(&bob).await.unwrap().unwrap_or_default().free;
@@ -59,10 +59,10 @@ async fn main() {
assert!(report.block_hash.is_some());
assert!(report.events.is_some());
assert!(format!("{dispatch_error:?}").contains("BadOrigin"));
+ println!("[+] BadOrigin error: Bob can't force set balance");
},
_ => panic!("Expected Failed Extrinisc Error"),
}
- println!("[+] BadOrigin error: Bob can't force set balance");
//BelowMinimum
api.set_signer(alice_signer.into());
@@ -80,5 +80,9 @@ async fn main() {
},
_ => panic!("Expected Failed Extrinisc Error"),
}
- println!("[+] BelowMinimum error: balance (999999) is below the existential deposit");
+ let existential_deposit = api.get_existential_deposit().await.unwrap();
+ println!(
+ "[+] BelowMinimum error: balance (999999) is below the existential deposit ({})",
+ &existential_deposit
+ );
}
diff --git a/testing/async/examples/pallet_balances_tests.rs b/testing/async/examples/pallet_balances_tests.rs
index 0eae6abca..f379a9e78 100644
--- a/testing/async/examples/pallet_balances_tests.rs
+++ b/testing/async/examples/pallet_balances_tests.rs
@@ -15,15 +15,65 @@
//! Tests for the pallet balances interface functions.
+use sp_keyring::AccountKeyring;
use substrate_api_client::{
- ac_primitives::AssetRuntimeConfig, rpc::JsonrpseeClient, Api, GetBalance,
+ ac_primitives::AssetRuntimeConfig, extrinsic::BalancesExtrinsics, rpc::JsonrpseeClient, Api,
+ GetAccountInformation, GetBalance, SubmitAndWatch, XtStatus,
};
#[tokio::main]
async fn main() {
// Setup
let client = JsonrpseeClient::with_default_url().await.unwrap();
- let api = Api::::new(client).await.unwrap();
+ let mut api = Api::::new(client).await.unwrap();
- let _ed = api.get_existential_deposit().await.unwrap();
+ let ed = api.get_existential_deposit().await.unwrap();
+ println!("[+] Existential deposit is {}\n", ed);
+
+ let alice = AccountKeyring::Alice.to_account_id();
+ let alice_signer = AccountKeyring::Alice.pair();
+ api.set_signer(alice_signer.into());
+ let balance_of_alice = api.get_account_data(&alice).await.unwrap().unwrap().free;
+ println!("[+] Alice's Free Balance is {}\n", balance_of_alice);
+
+ let bob = AccountKeyring::Bob.to_account_id();
+ let balance_of_bob = api.get_account_data(&bob).await.unwrap().unwrap_or_default().free;
+ println!("[+] Bob's Free Balance is {}\n", balance_of_bob);
+
+ // Rough estimate of fees for three transactions
+ let fee_estimate = 3 * 2000000000000;
+
+ let xt = api
+ .balance_transfer_keep_alive(bob.clone().into(), balance_of_alice / 2 - fee_estimate)
+ .await
+ .unwrap();
+ let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await;
+ // This call should succeed as alice has enough money
+ assert!(report.is_ok());
+
+ let balance_of_alice = api.get_account_data(&alice).await.unwrap().unwrap().free;
+ println!("[+] Alice's Free Balance is {}\n", balance_of_alice);
+
+ let xt = api
+ .balance_transfer_keep_alive(bob.clone().into(), balance_of_alice - fee_estimate)
+ .await
+ .unwrap();
+ let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await;
+ // This call should fail as alice would fall below the existential deposit
+ assert!(report.is_err());
+
+ let xt = api
+ .balance_transfer_allow_death(bob.clone().into(), balance_of_alice - fee_estimate)
+ .await
+ .unwrap();
+ let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await;
+ // With allow_death the call should succeed
+ assert!(result.is_ok());
+
+ let alice_account = api.get_account_data(&alice).await.unwrap();
+ // Alice account should not exist anymore so we excpect an error
+ assert!(alice_account.is_none());
+
+ let balance_of_bob = api.get_account_data(&bob).await.unwrap().unwrap_or_default().free;
+ println!("[+] Bob's Free Balance is {}\n", balance_of_bob);
}