Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: build chain extension method #121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 33 additions & 32 deletions pop-api/integration-tests/src/local_fungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,25 @@ use pop_primitives::error::{
const ASSET_ID: AssetId = 1;
const CONTRACT: &str = "contracts/fungibles/target/ink/fungibles.wasm";

fn decoded<T: Decode>(result: ExecReturnValue) -> T {
match <T>::decode(&mut &result.data[2..]) {
Ok(value) => value,
Err(_) => panic!("\nTest failed by trying to decode `{:?}` into `T`\n", result),
}
fn decoded<T: Decode>(result: ExecReturnValue) -> Result<T, String> {
<T>::decode(&mut &result.data[2..])
.map_err(|_| format!("\nTest failed by trying to decode `{:?}` into `T`\n", result))
}

// Call total_supply contract message.
fn total_supply(addr: AccountId32, asset_id: AssetId) -> Balance {
let function = function_selector("total_supply");
let params = [function, asset_id.encode()].concat();
let result = bare_call(addr, params, 0).expect("should work");
decoded::<Balance>(result)
decoded::<Balance>(result).unwrap()
}

// Call balance_of contract message.
fn balance_of(addr: AccountId32, asset_id: AssetId, owner: AccountId32) -> Balance {
let function = function_selector("balance_of");
let params = [function, asset_id.encode(), owner.encode()].concat();
let result = bare_call(addr, params, 0).expect("should work");
decoded::<Balance>(result)
decoded::<Balance>(result).unwrap()
}

// Call allowance contract message.
Expand All @@ -41,31 +39,31 @@ fn allowance(
let function = function_selector("allowance");
let params = [function, asset_id.encode(), owner.encode(), spender.encode()].concat();
let result = bare_call(addr, params, 0).expect("should work");
decoded::<Balance>(result)
decoded::<Balance>(result).unwrap()
}

// Call token_name contract message.
fn token_name(addr: AccountId32, asset_id: AssetId) -> Vec<u8> {
let function = function_selector("token_name");
let params = [function, asset_id.encode()].concat();
let result = bare_call(addr, params, 0).expect("should work");
decoded::<Vec<u8>>(result)
decoded::<Vec<u8>>(result).unwrap()
}

// Call token_symbol contract message.
fn token_symbol(addr: AccountId32, asset_id: AssetId) -> Vec<u8> {
let function = function_selector("token_symbol");
let params = [function, asset_id.encode()].concat();
let result = bare_call(addr, params, 0).expect("should work");
decoded::<Vec<u8>>(result)
decoded::<Vec<u8>>(result).unwrap()
}

// Call token_decimals contract message.
fn token_decimals(addr: AccountId32, asset_id: AssetId) -> u8 {
let function = function_selector("token_decimals");
let params = [function, asset_id.encode()].concat();
let result = bare_call(addr, params, 0).expect("should work");
decoded::<u8>(result)
decoded::<u8>(result).unwrap()
}

fn transfer(
Expand Down Expand Up @@ -327,26 +325,26 @@ fn transfer_works() {
// Asset does not exist.
assert_eq!(
decoded::<Error>(transfer(addr.clone(), 1, BOB, amount,)),
Module { index: 52, error: 3 },
Ok(Module { index: 52, error: 3 }),
);
// Create asset with Alice as owner and mint `amount` to contract address.
let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount);
// Asset is not live, i.e. frozen or being destroyed.
freeze_asset(ALICE, asset);
assert_eq!(
decoded::<Error>(transfer(addr.clone(), asset, BOB, amount,)),
Module { index: 52, error: 16 },
Ok(Module { index: 52, error: 16 }),
);
thaw_asset(ALICE, asset);
// Not enough balance.
assert_eq!(
decoded::<Error>(transfer(addr.clone(), asset, BOB, amount + 1 * UNIT)),
Module { index: 52, error: 0 },
Ok(Module { index: 52, error: 0 }),
);
// Not enough balance due to ED.
assert_eq!(
decoded::<Error>(transfer(addr.clone(), asset, BOB, amount)),
Module { index: 52, error: 0 },
Ok(Module { index: 52, error: 0 }),
);
// Successful transfer.
let balance_before_transfer = Assets::balance(asset, &BOB);
Expand All @@ -357,13 +355,13 @@ fn transfer_works() {
// Transfer asset to account that does not exist.
assert_eq!(
decoded::<Error>(transfer(addr.clone(), asset, FERDIE, amount / 4)),
Token(CannotCreate)
Ok(Token(CannotCreate))
);
// Asset is not live, i.e. frozen or being destroyed.
start_destroy_asset(ALICE, asset);
assert_eq!(
decoded::<Error>(transfer(addr.clone(), asset, BOB, amount / 4)),
Module { index: 52, error: 16 },
Ok(Module { index: 52, error: 16 }),
);
});
}
Expand All @@ -377,10 +375,13 @@ fn approve_works() {
// Asset does not exist.
assert_eq!(
decoded::<Error>(approve(addr.clone(), 0, BOB, amount)),
Module { index: 52, error: 3 },
Ok(Module { index: 52, error: 3 }),
);
let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount);
assert_eq!(decoded::<Error>(approve(addr.clone(), asset, BOB, amount)), ConsumerRemaining);
assert_eq!(
decoded::<Error>(approve(addr.clone(), asset, BOB, amount)),
Ok(ConsumerRemaining)
);

let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]);
// Create asset with Alice as owner and mint `amount` to contract address.
Expand All @@ -389,7 +390,7 @@ fn approve_works() {
freeze_asset(ALICE, asset);
assert_eq!(
decoded::<Error>(approve(addr.clone(), asset, BOB, amount)),
Module { index: 52, error: 16 },
Ok(Module { index: 52, error: 16 }),
);
thaw_asset(ALICE, asset);
// Successful approvals:
Expand All @@ -403,7 +404,7 @@ fn approve_works() {
start_destroy_asset(ALICE, asset);
assert_eq!(
decoded::<Error>(approve(addr.clone(), asset, BOB, amount)),
Module { index: 52, error: 16 },
Ok(Module { index: 52, error: 16 }),
);
});
}
Expand All @@ -417,12 +418,12 @@ fn increase_allowance_works() {
// Asset does not exist.
assert_eq!(
decoded::<Error>(increase_allowance(addr.clone(), 0, BOB, amount)),
Module { index: 52, error: 3 },
Ok(Module { index: 52, error: 3 }),
);
let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount);
assert_eq!(
decoded::<Error>(increase_allowance(addr.clone(), asset, BOB, amount)),
ConsumerRemaining
Ok(ConsumerRemaining)
);

let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]);
Expand All @@ -432,7 +433,7 @@ fn increase_allowance_works() {
freeze_asset(ALICE, asset);
assert_eq!(
decoded::<Error>(increase_allowance(addr.clone(), asset, BOB, amount)),
Module { index: 52, error: 16 },
Ok(Module { index: 52, error: 16 }),
);
thaw_asset(ALICE, asset);
// Successful approvals:
Expand All @@ -452,7 +453,7 @@ fn increase_allowance_works() {
start_destroy_asset(ALICE, asset);
assert_eq!(
decoded::<Error>(increase_allowance(addr.clone(), asset, BOB, amount)),
Module { index: 52, error: 16 },
Ok(Module { index: 52, error: 16 }),
);
});
}
Expand Down Expand Up @@ -530,7 +531,7 @@ fn token_metadata_works() {
// // Minting can only be done by the owner.
// assert_eq!(
// decoded::<Error>(transfer_from(addr.clone(), asset, None, Some(BOB), amount, &[0u8])),
// Module { index: 52, error: 2 },
// Ok(Module { index: 52, error: 2 }),
// );
// // Minimum balance of an asset can not be zero.
// assert_eq!(
Expand All @@ -542,7 +543,7 @@ fn token_metadata_works() {
// freeze_asset(addr.clone(), asset);
// assert_eq!(
// decoded::<Error>(transfer_from(addr.clone(), asset, None, Some(BOB), amount, &[0u8])),
// Module { index: 52, error: 16 },
// Ok(Module { index: 52, error: 16 }),
// );
// thaw_asset(addr.clone(), asset);
// // Successful mint.
Expand All @@ -567,7 +568,7 @@ fn token_metadata_works() {
// start_destroy_asset(addr.clone(), asset);
// assert_eq!(
// decoded::<Error>(transfer_from(addr.clone(), asset, None, Some(BOB), amount, &[0u8])),
// Module { index: 52, error: 16 },
// Ok(Module { index: 52, error: 16 }),
// );
// });
// }
Expand All @@ -582,27 +583,27 @@ fn token_metadata_works() {
// // No balance to pay for fees.
// assert_eq!(
// decoded::<Error>(create(addr.clone(), ASSET_ID, addr.clone(), 1)),
// Module { index: 10, error: 2 },
// Ok(Module { index: 10, error: 2 }),
// );
// // Instantiate a contract without balance (relay token).
// let addr = instantiate(CONTRACT, 100, vec![2]);
// // No balance to pay the deposit.
// assert_eq!(
// decoded::<Error>(create(addr.clone(), ASSET_ID, addr.clone(), 1)),
// Module { index: 10, error: 2 },
// Ok(Module { index: 10, error: 2 }),
// );
// // Instantiate a contract with balance.
// let addr =
// instantiate(CONTRACT, INIT_VALUE, vec![1]);
// assert_eq!(
// decoded::<Error>(create(addr.clone(), ASSET_ID, BOB, 0)),
// Module { index: 52, error: 7 },
// Ok(Module { index: 52, error: 7 }),
// );
// create_asset(ALICE, ASSET_ID, 1);
// // Asset ID is already taken.
// assert_eq!(
// decoded::<Error>(create(addr.clone(), ASSET_ID, BOB, 1)),
// Module { index: 52, error: 5 },
// Ok(Module { index: 52, error: 5 }),
// );
// // The minimal balance for an asset must be non zero.
// let new_asset = 2;
Expand Down
18 changes: 18 additions & 0 deletions pop-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

use ink::env::chain_extension::{ChainExtensionMethod, FromStatusCode};

use constants::DECODING_FAILED;
use ink::env::chain_extension::FromStatusCode;
#[cfg(feature = "assets")]
Expand Down Expand Up @@ -27,6 +29,22 @@ mod constants {
pub(crate) const FUNGIBLES: u8 = 150;
}

/// Helper method to build `ChainExtensionMethod`.
///
/// Parameters:
/// - 'version': The version of the chain extension
/// - 'function': The ID of the function
/// - 'module': The index of the runtime module
/// - 'dispatchable': The index of the module dispatchable functions
fn build_extension_method(
chungquantin marked this conversation as resolved.
Show resolved Hide resolved
version: u8,
function: u8,
module: u8,
dispatchable: u8,
) -> ChainExtensionMethod<(), (), (), false> {
ChainExtensionMethod::build(u32::from_le_bytes([version, function, module, dispatchable]))
}

/// Represents a status code returned by the runtime.
///
/// `StatusCode` encapsulates a `u32` value that indicates the status of an operation performed
Expand Down
38 changes: 27 additions & 11 deletions pop-api/src/v0/assets/fungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ use crate::{
use constants::*;
pub use metadata::*;

/// Helper method to build a dispatch call `ChainExtensionMethod` for fungibles `v0`
///
/// Parameters:
/// - 'dispatchable': The index of the module dispatchable functions
fn build_dispatch(dispatchable: u8) -> ChainExtensionMethod<(), (), (), false> {
crate::v0::build_dispatch(FUNGIBLES, dispatchable)
}

/// Helper method to build a dispatch call `ChainExtensionMethod` for fungibles `v0``
///
/// Parameters:
/// - 'state_query': The index of the runtime state query
fn build_read_state(state_query: u8) -> ChainExtensionMethod<(), (), (), false> {
crate::v0::build_read_state(FUNGIBLES, state_query)
}

/// Local Fungibles:
/// 1. PSP-22 Interface
/// 2. PSP-22 Metadata Interface
Expand Down Expand Up @@ -60,7 +76,7 @@ mod constants {
/// The total supply of the token, or an error if the operation fails.
#[inline]
pub fn total_supply(id: AssetId) -> Result<Balance> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, READ_STATE, FUNGIBLES, TOTAL_SUPPLY]))
build_read_state(TOTAL_SUPPLY)
.input::<AssetId>()
.output::<Result<Vec<u8>>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -79,7 +95,7 @@ pub fn total_supply(id: AssetId) -> Result<Balance> {
/// The balance of the specified account, or an error if the operation fails.
#[inline]
pub fn balance_of(id: AssetId, owner: AccountId) -> Result<Balance> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, READ_STATE, FUNGIBLES, BALANCE_OF]))
build_read_state(BALANCE_OF)
.input::<(AssetId, AccountId)>()
.output::<Result<Vec<u8>>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -99,7 +115,7 @@ pub fn balance_of(id: AssetId, owner: AccountId) -> Result<Balance> {
/// The remaining allowance, or an error if the operation fails.
#[inline]
pub fn allowance(id: AssetId, owner: AccountId, spender: AccountId) -> Result<Balance> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, READ_STATE, FUNGIBLES, ALLOWANCE]))
build_read_state(ALLOWANCE)
.input::<(AssetId, AccountId, AccountId)>()
.output::<Result<Vec<u8>>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -119,7 +135,7 @@ pub fn allowance(id: AssetId, owner: AccountId, spender: AccountId) -> Result<Ba
/// Returns `Ok(())` if successful, or an error if the transfer fails.
#[inline]
pub fn transfer(id: AssetId, target: AccountId, amount: Balance) -> Result<()> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, DISPATCH, FUNGIBLES, TRANSFER]))
build_dispatch(TRANSFER)
.input::<(AssetId, AccountId, Balance)>()
.output::<Result<()>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -140,7 +156,7 @@ pub fn transfer(id: AssetId, target: AccountId, amount: Balance) -> Result<()> {
/// Returns `Ok(())` if successful, or an error if the transfer fails.
#[inline]
pub fn transfer_from(id: AssetId, from: AccountId, to: AccountId, amount: Balance) -> Result<()> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, DISPATCH, FUNGIBLES, TRANSFER_FROM]))
build_dispatch(TRANSFER_FROM)
.input::<(AssetId, AccountId, AccountId, Balance)>()
.output::<Result<()>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -158,7 +174,7 @@ pub fn transfer_from(id: AssetId, from: AccountId, to: AccountId, amount: Balanc
/// Returns `Ok(())` if successful, or an error if the approval fails.
#[inline]
pub fn approve(id: AssetId, spender: AccountId, amount: Balance) -> Result<()> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, DISPATCH, FUNGIBLES, APPROVE]))
build_dispatch(APPROVE)
.input::<(AssetId, AccountId, Balance)>()
.output::<Result<()>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -176,7 +192,7 @@ pub fn approve(id: AssetId, spender: AccountId, amount: Balance) -> Result<()> {
/// Returns `Ok(())` if successful, or an error if the operation fails.
#[inline]
pub fn increase_allowance(id: AssetId, spender: AccountId, value: Balance) -> Result<()> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, DISPATCH, FUNGIBLES, INCREASE_ALLOWANCE]))
build_dispatch(INCREASE_ALLOWANCE)
.input::<(AssetId, AccountId, Balance)>()
.output::<Result<()>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -194,7 +210,7 @@ pub fn increase_allowance(id: AssetId, spender: AccountId, value: Balance) -> Re
/// Returns `Ok(())` if successful, or an error if the operation fails.
#[inline]
pub fn decrease_allowance(id: AssetId, spender: AccountId, value: Balance) -> Result<()> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, DISPATCH, FUNGIBLES, DECREASE_ALLOWANCE]))
build_dispatch(DECREASE_ALLOWANCE)
.input::<(AssetId, AccountId, Balance)>()
.output::<Result<()>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -212,7 +228,7 @@ pub mod metadata {
/// The name of the token as a byte vector, or an error if the operation fails.
#[inline]
pub fn token_name(id: AssetId) -> Result<Vec<u8>> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, READ_STATE, FUNGIBLES, TOKEN_NAME]))
build_read_state(TOKEN_NAME)
.input::<AssetId>()
.output::<Result<Vec<u8>>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -229,7 +245,7 @@ pub mod metadata {
/// The symbol of the token as a byte vector, or an error if the operation fails.
#[inline]
pub fn token_symbol(id: AssetId) -> Result<Vec<u8>> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, READ_STATE, FUNGIBLES, TOKEN_SYMBOL]))
build_read_state(TOKEN_SYMBOL)
.input::<AssetId>()
.output::<Result<Vec<u8>>, true>()
.handle_error_code::<StatusCode>()
Expand All @@ -246,7 +262,7 @@ pub mod metadata {
/// The number of decimals of the token as a byte vector, or an error if the operation fails.
#[inline]
pub fn token_decimals(id: AssetId) -> Result<u8> {
ChainExtensionMethod::build(u32::from_le_bytes([V0, READ_STATE, FUNGIBLES, TOKEN_DECIMALS]))
build_read_state(TOKEN_DECIMALS)
.input::<AssetId>()
.output::<Result<Vec<u8>>, true>()
.handle_error_code::<StatusCode>()
Expand Down
1 change: 1 addition & 0 deletions pop-api/src/v0/assets/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#[cfg(feature = "fungibles")]
pub mod fungibles;

Loading
Loading