-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #85 from CoinFabrik/67-issue-21-transfer
67 issue 21 transfer
- Loading branch information
Showing
3 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
[package] | ||
name = "transfer" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["[your_name] <[your_email]>"] | ||
|
||
[lib] | ||
path = "lib.rs" | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"ink/std", | ||
"scale/std", | ||
"scale-info/std", | ||
] | ||
ink-as-dependency = [] | ||
e2e-tests = [] | ||
|
||
[dependencies] | ||
ink = { version = "4.3.0", default-features = false } | ||
scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = ["derive"] } | ||
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } | ||
|
||
[dev-dependencies] | ||
ink_e2e = "4.3.0" | ||
|
||
[profile.dev] | ||
overflow-checks = false | ||
|
||
[profile.release] | ||
overflow-checks = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Function `transfer` | ||
|
||
```rust | ||
pub fn transfer<E>(destination: E::AccountId, value: E::Balance) -> Result<()> | ||
``` | ||
|
||
## Description | ||
|
||
The `transfer` function serves as the core of this contract. When invoked, it initiates a balance transfer of the specified `value` from the contract's balance to the `destination` account. This function is especially useful in scenarios where users or other contracts need to transfer funds. | ||
|
||
## Related ink! functions | ||
|
||
- [`transfer`](https://paritytech.github.io/ink/ink_env/fn.transfer.html) | ||
|
||
## Test case | ||
|
||
The contract's functionality can be demonstrated with a simple test: | ||
|
||
```rust | ||
let contract = Transfer::new(); | ||
contract.transfer(1000); | ||
``` | ||
|
||
This test showcases the process of instantiating the contract and requesting a balance transfer. In real-world scenarios, the results would also account for transaction fees and other network considerations. | ||
|
||
## Comparison Integration vs E2E | ||
|
||
Ensuring the reliability and security of balance transfers is crucial. As such, rigorous testing is performed on both integration and end-to-end levels: | ||
|
||
- Integration Tests: In the integration test `transfer_works`, a testing environment is set up with a specific account balance. The `transfer` function is then invoked to transfer a specified value from the contract's balance to the caller. After the transfer, the test asserts that the balances of the accounts have changed as expected. | ||
|
||
- E2E Tests: In the end-to-end test `transfer_works`, the contract is set up with a given balance. The `transfer` function is then called to transfer a value of `1` to the caller. The test then verifies that the contract's balance has decreased by the transferred amount. | ||
|
||
| \# | Test | Integration | E2E | | ||
| --- | ------------------------------------- | :---------: | :-: | | ||
| 1 | Transfers funds to the caller account | ✅ | ✅ | | ||
|
||
## Result | ||
|
||
This functionality works as expected. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
#![cfg_attr(not(feature = "std"), no_std, no_main)] | ||
|
||
#[ink::contract] | ||
mod transfer { | ||
|
||
#[ink(storage)] | ||
pub struct Transfer {} | ||
|
||
impl Transfer { | ||
#[ink(constructor, payable)] | ||
pub fn new() -> Self { | ||
Self {} | ||
} | ||
|
||
#[ink(message)] | ||
pub fn transfer(&self, value: Balance) { | ||
self.env() | ||
.transfer(self.env().caller(), value) | ||
.unwrap_or_else(|err| panic!("transfer failed: {:?}", err)); | ||
} | ||
} | ||
|
||
impl Default for Transfer { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use ink::env::{ | ||
test::{get_account_balance, set_account_balance, set_callee, set_caller}, | ||
DefaultEnvironment, | ||
}; | ||
|
||
#[ink::test] | ||
fn transfer_works() { | ||
// Given | ||
let contract = Transfer::new(); | ||
let callee_account_id = AccountId::from([0x01; 32]); | ||
let caller_account_id = AccountId::from([0x02; 32]); | ||
set_callee::<DefaultEnvironment>(callee_account_id); | ||
set_caller::<DefaultEnvironment>(caller_account_id); | ||
set_account_balance::<DefaultEnvironment>(callee_account_id, 1000); | ||
set_account_balance::<DefaultEnvironment>(caller_account_id, 0); | ||
|
||
// When | ||
contract.transfer(100); | ||
|
||
// Then | ||
let callee_balance = | ||
get_account_balance::<DefaultEnvironment>(AccountId::from([0x34; 32])) | ||
.expect("Cannot get account balance"); | ||
let caller_balance = get_account_balance::<DefaultEnvironment>(caller_account_id) | ||
.expect("Cannot get account balance"); | ||
assert_eq!(callee_balance, 900); | ||
assert_eq!(caller_balance, 100); | ||
} | ||
} | ||
|
||
#[cfg(all(test, feature = "e2e-tests"))] | ||
mod e2e_tests { | ||
use ink_e2e::{build_message, AccountKeyring}; | ||
|
||
use super::*; | ||
|
||
type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>; | ||
|
||
#[ink_e2e::test] | ||
async fn transfer_works(mut client: Client<C, E>) -> E2EResult<()> { | ||
// Given | ||
let constructor = TransferRef::new(); | ||
|
||
let callee_account_id = client | ||
.instantiate("transfer", &ink_e2e::bob(), constructor, 1000, None) | ||
.await | ||
.expect("instantiate failed") | ||
.account_id; | ||
let caller_account_id = AccountKeyring::Bob.to_raw_public().into(); | ||
|
||
let initial_callee_balance = client | ||
.balance(callee_account_id) | ||
.await | ||
.expect("Failed to get account balance"); | ||
let initial_caller_balance = client | ||
.balance(caller_account_id) | ||
.await | ||
.expect("Failed to get account balance"); | ||
|
||
// When | ||
let transfer_call = build_message::<TransferRef>(callee_account_id) | ||
.call(|contract| contract.transfer(1)); | ||
|
||
let _transfer_call_res = client | ||
.call(&ink_e2e::bob(), transfer_call, 0, None) | ||
.await | ||
.expect("transfer_call failed"); | ||
|
||
// Then | ||
let callee_balance = client | ||
.balance(callee_account_id) | ||
.await | ||
.expect("Failed to get account balance"); | ||
let caller_balance = client | ||
.balance(caller_account_id) | ||
.await | ||
.expect("Failed to get account balance"); | ||
|
||
assert_eq!(callee_balance, initial_callee_balance - 1); | ||
assert!(caller_balance < initial_caller_balance + 1); | ||
|
||
Ok(()) | ||
} | ||
} | ||
} |