Skip to content

Commit

Permalink
feat: spot order contract (#39)
Browse files Browse the repository at this point in the history
* feat(pop-api): add demo contract and unit test for placing a spot order

* fix(pop-api): update origin and weight to make XCM calls work

* feat: update ink deps to 5.0.0-rc3

* feat: update spot-order-contract to ink 5.0.0-rc.3

* style: formatting

* docs: add todo note

* test(extension): fix contract artifact path

---------

Co-authored-by: Frank Bell <frank@r0gue.io>
  • Loading branch information
peterwht and evilrobot-01 authored Mar 12, 2024
1 parent 27d5528 commit 0fce3f6
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 23 deletions.
4 changes: 2 additions & 2 deletions integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,9 @@ fn reserve_transfer_native_asset_from_relay_to_para() {
/// Reserve Transfers of native asset from Parachain to Relay should work
#[test]
fn reserve_transfer_native_asset_from_para_to_relay() {
init_tracing();
init_tracing();

// Setup: reserve transfer from relay to Pop, so that sovereign account accurate for return
// Setup: reserve transfer from relay to Pop, so that sovereign account accurate for return
// transfer
let amount_to_send: Balance = ROCOCO_ED * 1000;
fund_pop_network(RococoRelaySender::get(), amount_to_send, PopNetworkParaReceiver::get());
Expand Down
2 changes: 1 addition & 1 deletion pop-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"

[dependencies]
enumflags2 = { version = "0.7.7" }
ink = { version = "4.3.0", default-features = false }
ink = { version = "5.0.0-rc.3", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"] }
sp-io = { version = "23.0.0", default-features = false, features = ["disable_panic_handler", "disable_oom", "disable_allocator"] }
Expand Down
2 changes: 1 addition & 1 deletion pop-api/examples/balance-transfer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = ["[your_name] <[your_email]>"]
edition = "2021"

[dependencies]
ink = { version = "4.3.0", default-features = false }
ink = { version = "5.0.0-rc.3", default-features = false }
pop-api = { path = "../../../pop-api", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }
Expand Down
5 changes: 1 addition & 4 deletions pop-api/examples/nfts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ authors = ["[your_name] <[your_email]>"]
edition = "2021"

[dependencies]
ink = { version = "4.3.0", default-features = false }
ink = { version = "5.0.0-rc.3", default-features = false }
pop-api = { path = "../../../pop-api", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }

[dev-dependencies]
ink_e2e = "4.3.0"

[lib]
path = "lib.rs"

Expand Down
9 changes: 9 additions & 0 deletions pop-api/examples/place-spot-order/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore build artifacts from the local tests sub-crate.
/target/

# Ignore backup files creates by cargo fmt.
**/*.rs.bk

# Remove Cargo.lock when creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
25 changes: 25 additions & 0 deletions pop-api/examples/place-spot-order/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "pop_api_spot_order_example"
version = "0.1.0"
authors = ["[your_name] <[your_email]>"]
edition = "2021"

[dependencies]
ink = { version = "5.0.0-rc.3", default-features = false }
pop-api = { path = "../../../pop-api", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
"pop-api/std",
"scale/std",
"scale-info/std",
]
ink-as-dependency = []
e2e-tests = []
67 changes: 67 additions & 0 deletions pop-api/examples/place-spot-order/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

use pop_api::nfts;

#[derive(Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum ContractError {
InvalidCollection,
ItemAlreadyExists,
NftsError(nfts::Error),
NotOwner,
}

impl From<nfts::Error> for ContractError {
fn from(value: nfts::Error) -> Self {
ContractError::NftsError(value)
}
}

#[ink::contract(env = pop_api::Environment)]
mod pop_api_spot_order_example {
use super::ContractError;

#[ink(storage)]
#[derive(Default)]
pub struct PopApiSpotOrderExample;

impl PopApiSpotOrderExample {
#[ink(constructor, payable)]
pub fn new() -> Self {
ink::env::debug_println!("Contract::new");
Default::default()
}

#[ink(message)]
pub fn place_spot_order(
&mut self,
max_amount: Balance,
para_id: u32,
) -> Result<(), ContractError> {
ink::env::debug_println!(
"Contract::place_spot_order: max_amount {:?} para_id: {:?} ",
max_amount,
para_id,
);

let res = pop_api::cross_chain::coretime::place_spot_order(max_amount, para_id);
ink::env::debug_println!(
"Contract::place_spot_order: res {:?} ",
res,
);

ink::env::debug_println!("Contract::place_spot_order end");
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[ink::test]
fn default_works() {
PopApiSpotOrderExample::new();
}
}
}
5 changes: 1 addition & 4 deletions pop-api/examples/read-runtime-state/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ authors = ["[your_name] <[your_email]>"]
edition = "2021"

[dependencies]
ink = { version = "4.3.0", default-features = false }
ink = { version = "5.0.0-rc.3", default-features = false }
pop-api = { path = "../../../pop-api", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }

[dev-dependencies]
ink_e2e = "4.3.0"

[lib]
path = "lib.rs"

Expand Down
8 changes: 4 additions & 4 deletions pop-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ impl ink::env::Environment for Environment {
type ChainExtension = PopApi;
}

#[ink::chain_extension]
#[ink::chain_extension(extension = 909)]
pub trait PopApi {
type ErrorCode = PopApiError;

#[ink(extension = 0)]
#[ink(function = 0)]
#[allow(private_interfaces)]
fn dispatch(call: RuntimeCall) -> Result<()>;

#[ink(extension = 1)]
#[ink(function = 1)]
#[allow(private_interfaces)]
fn read_state(key: RuntimeStateKeys) -> Result<Vec<u8>>;

#[ink(extension = 2)]
#[ink(function = 2)]
#[allow(private_interfaces)]
fn send_xcm(xcm: CrossChainMessage) -> Result<()>;
}
Expand Down
81 changes: 74 additions & 7 deletions runtime/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl TryFrom<u16> for v0::FuncId {
fn dispatch_call<T, E>(
env: &mut Environment<E, BufInBufOutState>,
call: RuntimeCall,
origin: RuntimeOrigin,
log_prefix: &str,
) -> Result<(), DispatchError>
where
Expand All @@ -118,9 +119,6 @@ where

log::debug!(target:LOG_TARGET, "{} inputted RuntimeCall: {:?}", log_prefix, call);

// contract is the origin by default
let origin: RuntimeOrigin = RawOrigin::Signed(env.ext().address().clone()).into();

match call.dispatch(origin) {
Ok(info) => {
log::debug!(target:LOG_TARGET, "{} success, actual weight: {:?}", log_prefix, info.actual_weight);
Expand Down Expand Up @@ -182,7 +180,10 @@ where
// read the input as RuntimeCall
let call: RuntimeCall = env.read_as_unbounded(len)?;

dispatch_call::<T, E>(&mut env, call, LOG_PREFIX)
// contract is the origin by default
let origin: RuntimeOrigin = RawOrigin::Signed(env.ext().address().clone()).into();

dispatch_call::<T, E>(&mut env, call, origin, LOG_PREFIX)
}

fn read_state<T, E>(env: Environment<E, InitState>) -> Result<(), DispatchError>
Expand Down Expand Up @@ -320,7 +321,7 @@ where
.buy_execution(assets.clone().into(), Unlimited)

Check warning on line 321 in runtime/src/extensions.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `cumulus_primitives_core::Asset`

warning: useless conversion to the same type: `cumulus_primitives_core::Asset` --> runtime/src/extensions.rs:321:20 | 321 | .buy_execution(assets.clone().into(), Unlimited) | ^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `assets.clone()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion = note: `#[warn(clippy::useless_conversion)]` on by default
.transact(
SovereignAccount,
Weight::from_parts(25_000_000, 10_000),
Weight::from_parts(250_000_000, 10_000),
message.encode().into(),
)
.refund_surplus()
Expand All @@ -330,13 +331,16 @@ where
},
};

// TODO: revisit to replace with signed contract origin
let origin: RuntimeOrigin = RawOrigin::Root.into();

// Generate runtime call to dispatch
let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::send {
dest: Box::new(dest),
message: Box::new(VersionedXcm::V4(message)),
});

dispatch_call::<T, E>(&mut env, call, LOG_PREFIX)
dispatch_call::<T, E>(&mut env, call, origin, LOG_PREFIX)
}

#[cfg(test)]
Expand Down Expand Up @@ -619,7 +623,7 @@ mod tests {
let _ = env_logger::try_init();

let (wasm_binary, _) = load_wasm_module::<Runtime>(
"../pop-api/examples/read-runtime-state/target/ink/pop_api_read_state_example.wasm",
"../pop-api/examples/read-runtime-state/target/ink/pop_api_extension_demo.wasm",
)
.unwrap();

Expand Down Expand Up @@ -670,4 +674,67 @@ mod tests {
assert!(!result.result.unwrap().did_revert(), "Contract reverted!");
});
}

#[test]
#[ignore]
fn place_spot_order_from_contract_works() {
new_test_ext().execute_with(|| {
let _ = env_logger::try_init();

let (wasm_binary, _) = load_wasm_module::<Runtime>(
"../pop-api/examples/place-spot-order/target/ink/pop_api_spot_order_example.wasm",
)
.unwrap();

let init_value = 100 * UNIT;

let result = Contracts::bare_instantiate(
ALICE,
init_value,
GAS_LIMIT,
None,
Code::Upload(wasm_binary),
function_selector("new"),
vec![],
DEBUG_OUTPUT,
pallet_contracts::CollectEvents::Skip,
)
.result
.unwrap();

assert!(!result.result.did_revert(), "deploying contract reverted {:?}", result);

let addr = result.account_id;

let function = function_selector("place_spot_order");

let max_amount = 1 * UNIT;
let para_id = 2000;

let params = [function, max_amount.encode(), para_id.encode()].concat();

let result = Contracts::bare_call(
ALICE,
addr.clone(),
0,
Weight::from_parts(100_000_000_000, 3 * 1024 * 1024),
None,
params,
DEBUG_OUTPUT,
pallet_contracts::CollectEvents::Skip,
pallet_contracts::Determinism::Enforced,
);

if DEBUG_OUTPUT == pallet_contracts::DebugInfo::UnsafeDebug {
log::debug!(
"Contract debug buffer - {:?}",
String::from_utf8(result.debug_message.clone())
);
log::debug!("result: {:?}", result);
}

// check for revert
assert!(!result.result.unwrap().did_revert(), "Contract reverted!");
});
}
}

0 comments on commit 0fce3f6

Please sign in to comment.