Skip to content

Commit

Permalink
Merge pull request #93 from eigerco/iv-transfer
Browse files Browse the repository at this point in the history
Iv transfer
  • Loading branch information
35359595 authored Nov 7, 2023
2 parents 427e1d8 + de477b9 commit 01c4c91
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 23 deletions.
22 changes: 11 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
bcs = { git = "https://github.com/eigerco/bcs.git", default-features = false, branch = "master" }
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive",] }
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] }
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
arrayref = "^0.3"
frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v1.0.0' }
sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v1.0.0' }
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v1.0.0' }
frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }
frame-support = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }
frame-system = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }
sp-std = { default-features = false, git = 'https://github.com/paritytech/polkadot-sdk.git', branch = 'release-polkadot-v1.3.0' }
sp-core = { default-features = false, git = 'https://github.com/paritytech/polkadot-sdk.git', branch = 'release-polkadot-v1.3.0' }
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/polkadot-sdk.git', branch = 'release-polkadot-v1.3.0' }

# MoveVM dependencies
move-core-types = { default-features = false, git = 'https://github.com/eigerco/substrate-move.git', features = ["address32"] }
Expand All @@ -32,10 +32,10 @@ move-vm-backend = { default-features = false, git = 'https://github.com/eigerco/

[dev-dependencies]
hex = "0.4"
sp-core = { version = "21.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
sp-io = { version = "23.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
sp-runtime = { version = "24.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
pallet-balances = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }
sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }
pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.3.0" }

[features]
default = ["std"]
Expand Down
39 changes: 27 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ pub mod pallet {
use frame_support::{
dispatch::{DispatchResultWithPostInfo, PostDispatchInfo},
pallet_prelude::*,
traits::{Currency, ReservableCurrency},
traits::{Currency, ExistenceRequirement, ReservableCurrency},
};
use frame_system::pallet_prelude::*;
use move_core_types::account_address::AccountAddress;
use move_vm_backend::Mvm;
use move_vm_types::gas::UnmeteredGasMeter;
use sp_core::crypto::AccountId32;
use sp_runtime::{DispatchResult, SaturatedConversion};
use sp_std::{default::Default, vec::Vec};

use super::*;
Expand All @@ -51,7 +52,7 @@ pub mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config {
/// The currency mechanism.
type Currency: ReservableCurrency<Self::AccountId>;
type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

/// Because this pallet emits events, it depends on the runtime's definition of an event.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
Expand Down Expand Up @@ -120,10 +121,13 @@ pub mod pallet {
// - put Mvm initialization to some other place, to avoid doing it every time
// - Substrate address to Move address conversion is missing in the move-cli
let vm = Mvm::new(storage).map_err(|_err| Error::<T>::PublishModuleFailed)?;
let encoded = who.encode();

ensure!(encoded.len().eq(&32), Error::<T>::InvalidAccountSize);

vm.publish_module(
bytecode.as_slice(),
address::to_move_address(&who),
Self::native_to_move(AccountId32::new(array_ref![encoded, 0, 32].to_owned()))?,
&mut UnmeteredGasMeter, // TODO(asmie): gas handling
)
.map_err(|_err| Error::<T>::PublishModuleFailed)?;
Expand Down Expand Up @@ -152,6 +156,23 @@ pub mod pallet {

Ok(PostDispatchInfo::default())
}

#[pallet::call_index(3)]
#[pallet::weight(T::WeightInfo::transfer())]
pub fn transfer(
origin: OriginFor<T>,
recepient: [u8; 32], // AccountAddress
amount: u128,
) -> DispatchResult {
let from = ensure_signed(origin)?;
let recepient_account = AccountAddress::new(recepient);
T::Currency::transfer(
&from,
&Self::move_to_native(&recepient_account)?,
amount.saturated_into(),
ExistenceRequirement::KeepAlive,
)
}
}

#[pallet::error]
Expand Down Expand Up @@ -223,19 +244,13 @@ pub mod pallet {
}

/// Get balance of given account in native currency converted to u128
pub fn get_balance(of: T::AccountId) -> Result<u128, Error<T>> {
let encoded_balance = T::Currency::free_balance(&of).encode();
if encoded_balance.len().ne(&16usize) {
return Err(Error::BalanceConversionFailed);
}
Ok(u128::from_be_bytes(
array_ref!(encoded_balance, 0, 16).to_owned(),
))
pub fn get_balance(of: T::AccountId) -> u128 {
T::Currency::free_balance(&of).saturated_into::<u128>()
}

// Get balance of given Move account in native currecy converted to u128
pub fn get_move_balance(of: &AccountAddress) -> Result<u128, Error<T>> {
Self::get_balance(Self::move_to_native(of)?)
Ok(Self::get_balance(Self::move_to_native(of)?))
}

// Transparent conversion move -> native
Expand Down
9 changes: 9 additions & 0 deletions src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub trait WeightInfo {
fn execute() -> Weight;
fn publish_module() -> Weight;
fn publish_package() -> Weight;
fn transfer() -> Weight;
}

/// Weights for pallet_move using the Substrate node and recommended hardware.
Expand All @@ -64,6 +65,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Minimum execution time: 5_336_000 picoseconds.
Weight::from_parts(5_700_000, 0)
}
// TODO(ivan): regenerate with benchmarking
fn transfer() -> Weight {
Weight::from_parts(500_000, 0)
}
}

// For backwards compatibility and tests.
Expand All @@ -89,4 +94,8 @@ impl WeightInfo for () {
// Minimum execution time: 5_336_000 picoseconds.
Weight::from_parts(5_700_000, 0)
}
// TODO(ivan): regenerate with benchmarking
fn transfer() -> Weight {
Weight::from_parts(500_000, 0)
}
}
Binary file modified tests/assets/move/build/move/bytecode_modules/Empty.mv
Binary file not shown.
75 changes: 75 additions & 0 deletions tests/balances.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
mod mock;

use frame_support::{assert_err, assert_ok};
use mock::*;
use sp_runtime::{traits::BadOrigin, AccountId32, ArithmeticError};

const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
const BOB: AccountId32 = AccountId32::new([2u8; 32]);

#[test]
// Test transfering with existing balance
fn transfer_move_valid_amounts() {
new_test_ext().execute_with(|| {
const INITIAL: u128 = 1_000_000;
const SENDING: u128 = INITIAL / 10;
let signed_alice = RuntimeOrigin::signed(ALICE);
// Set Alice balance to predefined vaule
assert_ok!(Balances::force_set_balance(
RuntimeOrigin::root(),
ALICE,
INITIAL
));
let bob_move = MoveModule::native_to_move(BOB).unwrap();
// make sure Bob's balance is 0
assert_eq!(0, MoveModule::get_balance(BOB));
// Send 'SENDING' to Bob
assert_ok!(MoveModule::transfer(
signed_alice,
bob_move.into_bytes(),
SENDING
));
// verify
assert_eq!(SENDING, MoveModule::get_balance(BOB));
// Alice balance reduced
assert_eq!(MoveModule::get_balance(ALICE), INITIAL - SENDING);
// Move balances match
assert_eq!(SENDING, MoveModule::get_move_balance(&bob_move).unwrap());
assert_eq!(
MoveModule::get_move_balance(&MoveModule::native_to_move(ALICE).unwrap()).unwrap(),
INITIAL - SENDING
);
})
}

#[test]
// Invalid cases should fail
fn invalid_balances_transfer_move_fails() {
new_test_ext().execute_with(|| {
let bob_move = MoveModule::native_to_move(BOB).unwrap();
// root not accepted
assert_err!(
MoveModule::transfer(RuntimeOrigin::root(), bob_move.into_bytes(), u128::MAX),
BadOrigin
);
// signed but not enough balance
let signed_alice = RuntimeOrigin::signed(ALICE);
assert_err!(
MoveModule::transfer(signed_alice.clone(), bob_move.into_bytes(), 100000),
ArithmeticError::Underflow
);
// non-zero balance but sending more than free
const INITIAL: u128 = 1_000_000;
const SENDING: u128 = INITIAL * 10;
// Set Alice balance to predefined vaule
assert_ok!(Balances::force_set_balance(
RuntimeOrigin::root(),
ALICE,
INITIAL
));
assert_err!(
MoveModule::transfer(signed_alice, bob_move.into_bytes(), SENDING),
ArithmeticError::Underflow
);
})
}
1 change: 1 addition & 0 deletions tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl pallet_balances::Config for Test {
type MaxFreezes = ();
type RuntimeHoldReason = ();
type MaxHolds = ();
type RuntimeFreezeReason = ();
}

impl pallet_move::Config for Test {
Expand Down

0 comments on commit 01c4c91

Please sign in to comment.