mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 21:01:05 +00:00
Add ext_transfer call (#5169)
* contracts: Add ext_transfer call This call allows contracts to send balance to any account contract or not. Previously, the only way to do that was though ext_call. * Apply suggestions from code review Co-Authored-By: Nikolay Volf <nikvolf@gmail.com> * The define_env! macro does not allow for trailing comma * Update frame/contracts/src/exec.rs Co-Authored-By: Nikolay Volf <nikvolf@gmail.com> * Bump spec version * Do not use nested gas meter * Use explicit 0 or 1 as return value * Remove superflous intermediate binding Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
This commit is contained in:
committed by
GitHub
parent
7e2cd0edee
commit
b817763ea9
@@ -244,6 +244,20 @@ mod tests {
|
||||
|
||||
Ok((address, ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() }))
|
||||
}
|
||||
fn transfer(
|
||||
&mut self,
|
||||
to: &u64,
|
||||
value: u64,
|
||||
gas_meter: &mut GasMeter<Test>,
|
||||
) -> Result<(), DispatchError> {
|
||||
self.transfers.push(TransferEntry {
|
||||
to: *to,
|
||||
value,
|
||||
data: Vec::new(),
|
||||
gas_left: gas_meter.gas_left(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
fn call(
|
||||
&mut self,
|
||||
to: &u64,
|
||||
@@ -254,7 +268,7 @@ mod tests {
|
||||
self.transfers.push(TransferEntry {
|
||||
to: *to,
|
||||
value,
|
||||
data: data.to_vec(),
|
||||
data: data,
|
||||
gas_left: gas_meter.gas_left(),
|
||||
});
|
||||
// Assume for now that it was just a plain transfer.
|
||||
@@ -357,6 +371,14 @@ mod tests {
|
||||
) -> Result<(u64, ExecReturnValue), ExecError> {
|
||||
(**self).instantiate(code, value, gas_meter, input_data)
|
||||
}
|
||||
fn transfer(
|
||||
&mut self,
|
||||
to: &u64,
|
||||
value: u64,
|
||||
gas_meter: &mut GasMeter<Test>,
|
||||
) -> Result<(), DispatchError> {
|
||||
(**self).transfer(to, value, gas_meter)
|
||||
}
|
||||
fn call(
|
||||
&mut self,
|
||||
to: &u64,
|
||||
@@ -453,6 +475,59 @@ mod tests {
|
||||
}
|
||||
|
||||
const CODE_TRANSFER: &str = r#"
|
||||
(module
|
||||
;; ext_transfer(
|
||||
;; account_ptr: u32,
|
||||
;; account_len: u32,
|
||||
;; value_ptr: u32,
|
||||
;; value_len: u32,
|
||||
;;) -> u32
|
||||
(import "env" "ext_transfer" (func $ext_transfer (param i32 i32 i32 i32) (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
(func (export "call")
|
||||
(drop
|
||||
(call $ext_transfer
|
||||
(i32.const 4) ;; Pointer to "account" address.
|
||||
(i32.const 8) ;; Length of "account" address.
|
||||
(i32.const 12) ;; Pointer to the buffer with value to transfer
|
||||
(i32.const 8) ;; Length of the buffer with value to transfer.
|
||||
)
|
||||
)
|
||||
)
|
||||
(func (export "deploy"))
|
||||
|
||||
;; Destination AccountId to transfer the funds.
|
||||
;; Represented by u64 (8 bytes long) in little endian.
|
||||
(data (i32.const 4) "\07\00\00\00\00\00\00\00")
|
||||
|
||||
;; Amount of value to transfer.
|
||||
;; Represented by u64 (8 bytes long) in little endian.
|
||||
(data (i32.const 12) "\99\00\00\00\00\00\00\00")
|
||||
)
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn contract_transfer() {
|
||||
let mut mock_ext = MockExt::default();
|
||||
let _ = execute(
|
||||
CODE_TRANSFER,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
&mock_ext.transfers,
|
||||
&[TransferEntry {
|
||||
to: 7,
|
||||
value: 153,
|
||||
data: Vec::new(),
|
||||
gas_left: 49978,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
const CODE_CALL: &str = r#"
|
||||
(module
|
||||
;; ext_call(
|
||||
;; callee_ptr: u32,
|
||||
@@ -492,10 +567,10 @@ mod tests {
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn contract_transfer() {
|
||||
fn contract_call() {
|
||||
let mut mock_ext = MockExt::default();
|
||||
let _ = execute(
|
||||
CODE_TRANSFER,
|
||||
CODE_CALL,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
|
||||
@@ -405,6 +405,36 @@ define_env!(Env, <E: Ext>,
|
||||
}
|
||||
},
|
||||
|
||||
// Transfer some value to another account.
|
||||
//
|
||||
// If the value transfer was succesful zero is returned. Otherwise one is returned.
|
||||
// The scratch buffer is not touched. The receiver can be a plain account or
|
||||
// a contract.
|
||||
//
|
||||
// - account_ptr: a pointer to the address of the beneficiary account
|
||||
// Should be decodable as an `T::AccountId`. Traps otherwise.
|
||||
// - account_len: length of the address buffer.
|
||||
// - value_ptr: a pointer to the buffer with value, how much value to send.
|
||||
// Should be decodable as a `T::Balance`. Traps otherwise.
|
||||
// - value_len: length of the value buffer.
|
||||
ext_transfer(
|
||||
ctx,
|
||||
account_ptr: u32,
|
||||
account_len: u32,
|
||||
value_ptr: u32,
|
||||
value_len: u32
|
||||
) -> u32 => {
|
||||
let callee: <<E as Ext>::T as frame_system::Trait>::AccountId =
|
||||
read_sandbox_memory_as(ctx, account_ptr, account_len)?;
|
||||
let value: BalanceOf<<E as Ext>::T> =
|
||||
read_sandbox_memory_as(ctx, value_ptr, value_len)?;
|
||||
|
||||
match ctx.ext.transfer(&callee, value, ctx.gas_meter) {
|
||||
Ok(_) => Ok(0),
|
||||
Err(_) => Ok(1),
|
||||
}
|
||||
},
|
||||
|
||||
// Make a call to another contract.
|
||||
//
|
||||
// If the called contract runs to completion, then this returns the status code the callee
|
||||
|
||||
Reference in New Issue
Block a user