Skip to content
This repository was archived by the owner on Sep 28, 2023. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ members = [
"frame/pallet-xvm",
"frame/xc-asset-config",
"frame/contracts-migration",
"frame/pallet-xcm-transactor",
"frame/pallet-xcm-transactor/primitives",
# "frame/pallet-xcm-transactor/contracts-example",
"primitives/xcm",
"precompiles/assets-erc20",
"precompiles/dapps-staking",
Expand Down
66 changes: 66 additions & 0 deletions frame/pallet-xcm-transactor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[package]
name = "pallet-xcm-transactor"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = { workspace = true }
num_enum = { version = "0.6", default-features = false }
parity-scale-codec = { workspace = true }
scale-info = { workspace = true }

# substrate core
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }

# frame dependencies
frame-support = { workspace = true }
frame-system = { workspace = true }

# pallets
pallet-contracts = { workspace = true }
pallet-xcm = { workspace = true }

# xcm
xcm = { workspace = true }
xcm-executor = { workspace = true }

# types
xcm-ce-primitives = { path = "./primitives", default-features = false}

[features]
default = ["std"]
std = [
"num_enum/std",
"parity-scale-codec/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"frame-support/std",
"frame-system/std",
"xcm/std",
"xcm-executor/std",
"pallet-xcm/std",
"pallet-contracts/std",
"xcm-ce-primitives/std",
]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-xcm/runtime-benchmarks",
"pallet-contracts/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"pallet-xcm/try-runtime",
"pallet-contracts/try-runtime",
]
Empty file.
9 changes: 9 additions & 0 deletions frame/pallet-xcm-transactor/contracts-example/.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
34 changes: 34 additions & 0 deletions frame/pallet-xcm-transactor/contracts-example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "contracts-example"
version = "0.1.0"
authors = ["Ashutosh Varma <ashutoshvarma11@live.com>"]
edition = "2021"

[workspace]

[dependencies]
ink = { version = "~4.2.0", default-features = false }

num_enum = { version = "0.6", 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 }
xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.39", default-features = false }
xcm-ce-primitives = { path = "../primitives", default-features = false }

[lib]
path = "lib.rs"

[profile.release]
overflow-checks = false # Disable integer overflow checks.

[features]
default = ["std"]
std = [
"ink/std",
"num_enum/std",
"scale/std",
"scale-info/std",
"xcm/std",
"xcm-ce-primitives/std",
]
ink-as-dependency = []
122 changes: 122 additions & 0 deletions frame/pallet-xcm-transactor/contracts-example/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Astar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]

mod sdk;
pub use sdk::{Error as XcmCEError, XcmExtension as _XcmExtension};

#[ink::contract]
mod contracts {
use super::*;
use ink::{env::DefaultEnvironment, storage::Mapping};
use xcm::{latest::Weight, prelude::*};
use xcm_ce_primitives::{QueryConfig, ValidateSendInput};

type XcmExtension = _XcmExtension<DefaultEnvironment>;

#[ink(storage)]
#[derive(Default)]
pub struct Contracts {
value: bool,
expecting_query: Mapping<QueryId, bool>,
}

impl Contracts {
#[ink(constructor, selector = 0xFFFFFFFF)]
pub fn default() -> Self {
Self {
..Default::default()
}
}

#[ink(message, selector = 0x11111111)]
pub fn execute(&mut self, xcm: VersionedXcm<()>) -> Result<Weight, XcmCEError> {
let weight = XcmExtension::prepare_execute(xcm)?;
ink::env::debug_println!("[1/2] Prepared XCM");

XcmExtension::execute()?;
ink::env::debug_println!("[2/2] Execute XCM");

Ok(weight)
}

#[ink(message, selector = 0x22222222)]
pub fn send(
&mut self,
input: ValidateSendInput,
) -> Result<VersionedMultiAssets, XcmCEError> {
let fees = XcmExtension::validate_send(input)?;
ink::env::debug_println!("[1/2] Validate Send XCM");

XcmExtension::send()?;
ink::env::debug_println!("[2/2] Send XCM");

Ok(fees)
}

#[ink(message, selector = 0x33333333)]
pub fn query(
&mut self,
config: QueryConfig<AccountId, BlockNumber>,
dest: VersionedMultiLocation,
) -> Result<QueryId, XcmCEError> {
ink::env::debug_println!("[1/3] Registering Query..., {config:?}");
let query_id = XcmExtension::new_query(config, dest)?;
ink::env::debug_println!("[2/3] Registered Query");

self.expecting_query.insert(query_id, &true);
ink::env::debug_println!("[3/3] Save Query");

Ok(query_id)
}

#[ink(message, selector = 0x44444444)]
pub fn poll_response(&mut self, query_id: QueryId) -> Result<Response, XcmCEError> {
ink::env::debug_println!("[1/1] Response Recieved for QueryId - {query_id}");
XcmExtension::take_response(query_id)
}

#[ink(message, selector = 0x55555555)]
pub fn handle_response(
&mut self,
query_id: QueryId,
_responder: MultiLocation,
_response: Response,
) {
ink::env::debug_println!("[1/1] Response Recieved for QueryId - {query_id}");
assert!(XcmExtension::pallet_account_id() == self.env().caller());
match self.expecting_query.get(query_id) {
Some(expecting) if expecting == true => {
// NOTE: do not delete storage, because storage deposit
// refund will fail.
// self.expecting_query.remove(query_id);
self.value = !self.value;
}
_ => {
panic!("Not expecting response");
}
}
}

#[ink(message, selector = 0x66666666)]
pub fn get(&self) -> bool {
self.value
}
}
}
129 changes: 129 additions & 0 deletions frame/pallet-xcm-transactor/contracts-example/sdk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Astar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]

use core::marker::PhantomData;
use ink::env::{chain_extension::FromStatusCode, DefaultEnvironment, Environment};
use scale::{Decode, Encode};
use xcm::{latest::Weight, prelude::*};
use xcm_ce_primitives::{
create_error_enum, Command, QueryConfig, ValidateSendInput, XCM_EXTENSION_ID,
};

create_error_enum!(pub Error);

impl FromStatusCode for Error {
fn from_status_code(status_code: u32) -> Result<(), Self> {
match status_code {
0 => Ok(()),
code => Err(code.into()),
}
}
}

/// XCM Chain Extension Interface
pub struct XcmExtension<E = DefaultEnvironment, const ID: u16 = XCM_EXTENSION_ID>(PhantomData<E>);

impl<E: Environment, const ID: u16> XcmExtension<E, ID> {
const fn get_func_id(idx: u16) -> u32 {
((ID as u32) << 16) + (idx as u32)
}

pub fn prepare_execute(xcm: VersionedXcm<()>) -> Result<Weight, Error> {
let func_id: u32 = Self::get_func_id(Command::PrepareExecute.into());

// fn(VersionedXcm<()>) -> Result<Weight, Error>
::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<VersionedXcm<()>>()
.output::<Weight, false>()
.handle_error_code::<Error>()
.call(&(xcm))
}

pub fn execute() -> Result<(), Error> {
let func_id: u32 = Self::get_func_id(Command::Execute.into());

// fn() -> Result<(Weight), Error>
::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<()>()
.output::<(), false>()
.handle_error_code::<Error>()
.call(&())
}

pub fn validate_send(input: ValidateSendInput) -> Result<VersionedMultiAssets, Error> {
let func_id: u32 = Self::get_func_id(Command::ValidateSend.into());

// fn(ValidateSendInput) -> Result<VersionedMultiAssets, Error>
::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<ValidateSendInput>()
.output::<VersionedMultiAssets, false>()
.handle_error_code::<Error>()
.call(&(input))
}

pub fn send() -> Result<(), Error> {
let func_id: u32 = Self::get_func_id(Command::Send.into());

// fn() -> Result<(), Error>
::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<()>()
.output::<(), false>()
.handle_error_code::<Error>()
.call(&())
}

pub fn new_query(
config: QueryConfig<E::AccountId, E::BlockNumber>,
dest: VersionedMultiLocation,
) -> Result<QueryId, Error> {
let func_id: u32 = Self::get_func_id(Command::NewQuery.into());

// fn(QueryConfig, VersionedMultiLocation) -> Result<QueryId, Error>
::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<(
QueryConfig<E::AccountId, E::BlockNumber>,
VersionedMultiLocation,
)>()
.output::<QueryId, false>()
.handle_error_code::<Error>()
.call(&(config, dest))
}

pub fn take_response(query_id: QueryId) -> Result<Response, Error> {
let func_id: u32 = Self::get_func_id(Command::TakeResponse.into());

// fn(QueryId) -> Result<Response, Error>
::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<QueryId>()
.output::<Response, false>()
.handle_error_code::<Error>()
.call(&(query_id))
}

pub fn pallet_account_id() -> E::AccountId {
let func_id = Self::get_func_id(Command::PalletAccountId.into());

::ink::env::chain_extension::ChainExtensionMethod::build(func_id)
.input::<()>()
.output::<E::AccountId, false>()
.ignore_error_code()
.call(&())
}
}
Loading