Skip to content

Commit

Permalink
Assets chain extension
Browse files Browse the repository at this point in the history
  • Loading branch information
kacperzuk-neti committed Jun 26, 2024
1 parent c8068f7 commit af5e674
Show file tree
Hide file tree
Showing 12 changed files with 499 additions and 20 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions contracts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion contracts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
resolver = "2"
members = [
"msig_court"
"asset-timelock",
"msig_court",
]
9 changes: 9 additions & 0 deletions contracts/asset-timelock/.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
24 changes: 24 additions & 0 deletions contracts/asset-timelock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "asset-timelock"
version = "0.1.0"
authors = ["[your_name] <[your_email]>"]
edition = "2021"

[dependencies]
ink = { version = "5.0.0", default-features = false }
liberland-extension = { path = "../../liberland-extension/ink", default-features = false}

[dev-dependencies]
ink_e2e = { version = "5.0.0" }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
"liberland-extension/std",
]
ink-as-dependency = []
e2e-tests = []
130 changes: 130 additions & 0 deletions contracts/asset-timelock/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

#[cfg(test)]
mod mock;

#[ink::contract(env = liberland_extension::LiberlandEnvironment)]
mod asset_timelock {
use ink::storage::Mapping;
use liberland_extension::{AssetId, AssetsBalance};

pub type DepositId = u32;

#[derive(Debug, PartialEq, Eq, Clone)]
#[ink::scale_derive(Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(ink::storage::traits::StorageLayout))]
pub struct Deposit {
timestamp: Timestamp,
asset_id: AssetId,
recipient: AccountId,
amount: AssetsBalance,
}

#[derive(Debug, PartialEq, Eq, Clone)]
#[ink::scale_derive(Encode, Decode, TypeInfo)]
pub enum Error {
/// Funds not unlocked yet
TooEarly,
/// No such deposit found
NotFound,
/// Runtime call failed
CallFailed,
/// Arithmetic overflow
Overflow,
/// Unlock timestamp is before current timestamp
TimestampFromThePast,
}

impl From<liberland_extension::Error> for Error {
fn from(_: liberland_extension::Error) -> Self {
Self::CallFailed
}
}

pub type Result<T> = core::result::Result<T, Error>;

#[ink(storage)]
#[derive(Default)]
pub struct AssetTimelock {
next_deposit_id: DepositId,
deposits: Mapping<DepositId, Deposit>,
}

#[ink(event)]
pub struct Deposited {
#[ink(topic)]
depositor: AccountId,
#[ink(topic)]
recipient: AccountId,
deposit_id: DepositId,
asset_id: AssetId,
timestamp: Timestamp,
amount: AssetsBalance,
}

#[ink(event)]
pub struct Withdrawn {
#[ink(topic)]
recipient: AccountId,
deposit_id: DepositId,
asset_id: AssetId,
amount: AssetsBalance,
}

impl AssetTimelock {
#[ink(constructor)]
pub fn new() -> Self {
Default::default()
}

#[ink(message)]
pub fn get_deposit(&self, deposit_id: DepositId) -> Option<Deposit> {
self.deposits.get(deposit_id)
}

#[ink(message)]
pub fn deposit(
&mut self,
asset_id: AssetId,
recipient: AccountId,
amount: AssetsBalance,
timestamp: Timestamp,
) -> Result<DepositId> {
if timestamp < self.env().block_timestamp() {
return Err(Error::TimestampFromThePast);
}
let depositor = self.env().caller();
let contract_account = self.env().account_id();
let deposit_id = self.next_deposit_id;
self.next_deposit_id = self.next_deposit_id.checked_add(1).ok_or(Error::Overflow)?;
self.env().extension().asset_transfer_approved(
asset_id,
depositor,
contract_account,
amount,
)?;
self.deposits
.insert(deposit_id, &Deposit { timestamp, asset_id, recipient, amount });
self.env().emit_event(Deposited {
depositor,
deposit_id,
asset_id,
recipient,
timestamp,
amount,
});
Ok(deposit_id)
}

#[ink(message)]
pub fn withdraw(&mut self, deposit_id: DepositId) -> Result<()> {
let Deposit { asset_id, recipient, amount, timestamp } =
self.deposits.take(&deposit_id).ok_or(Error::NotFound)?;
if timestamp > self.env().block_timestamp() {
return Err(Error::TooEarly);
}
self.env().extension().asset_transfer(asset_id, recipient, amount)?;
Ok(())
}
}
}
21 changes: 21 additions & 0 deletions contracts/asset-timelock/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
pub struct MockedLiberlandExtensionSuccess;
impl ink::env::test::ChainExtension for MockedLiberlandExtensionSuccess {
fn ext_id(&self) -> u16 {
0
}

fn call(&mut self, _func_id: u16, _input: &[u8], _output: &mut Vec<u8>) -> u32 {
0
}
}

pub struct MockedLiberlandExtensionFail;
impl ink::env::test::ChainExtension for MockedLiberlandExtensionFail {
fn ext_id(&self) -> u16 {
0
}

fn call(&mut self, _func_id: u16, _input: &[u8], _output: &mut Vec<u8>) -> u32 {
1
}
}
44 changes: 44 additions & 0 deletions liberland-extension/ink/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,50 @@ pub trait Liberland {

#[ink(function = 1)]
fn llm_force_transfer(args: LLMForceTransferArguments);

#[ink(function = 2)]
fn asset_balance_of(
asset_id: AssetId,
account: AccountId,
) -> AssetsBalance;

#[ink(function = 3)]
fn asset_total_supply_of(
asset_id: AssetId
) -> AssetsBalance;

#[ink(function = 4)]
fn asset_approve_transfer(
asset_id: AssetId,
delegate: AccountId,
amount: Balance,
);

#[ink(function = 5)]
fn asset_cancel_approval(
asset_id: AssetId,
delegate: AccountId,
);

#[ink(function = 6)]
fn asset_transfer(
asset_id: AssetId,
target: AccountId,
amount: Balance
);
#[ink(function = 7)]
fn asset_transfer_approved(
asset_id: AssetId,
owner: AccountId,
destination: AccountId,
amount: Balance,
);
#[ink(function = 8)]
fn asset_transfer_keep_alive(
asset_id: AssetId,
target: AccountId,
amount: Balance
);
}

impl ink::env::chain_extension::FromStatusCode for Error {
Expand Down
6 changes: 4 additions & 2 deletions liberland-extension/ink/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use ink::env::Environment;

type AccountId = <ink::env::DefaultEnvironment as Environment>::AccountId;
type Balance = <ink::env::DefaultEnvironment as Environment>::Balance;
pub type AccountId = <ink::env::DefaultEnvironment as Environment>::AccountId;
pub type Balance = <ink::env::DefaultEnvironment as Environment>::Balance;
pub type AssetsBalance = u128;
pub type AssetId = u32;

#[derive(Debug, Clone, PartialEq, Eq)]
#[ink::scale_derive(Encode, Decode, TypeInfo)]
Expand Down
19 changes: 10 additions & 9 deletions liberland-extension/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,26 @@ publish = false
[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false }
frame-support = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
pallet-contracts = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
sp-std = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
sp-core = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
sp-runtime = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
frame-system = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
log = { version = "0.4.17", default-features = false }

pallet-assets = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
pallet-contracts = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
pallet-llm = { default-features = false, path = "../../substrate/frame/llm" }
sp-core = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
sp-runtime = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }
sp-std = { default-features = false, tag = "polkadot-v1.1.0", git = "https://github.com/paritytech/polkadot-sdk" }

[features]
default = ["std"]
std = [
"codec/std",
"frame-support/std",
"pallet-contracts/std",
"sp-std/std",
"sp-core/std",
"sp-runtime/std",
"frame-system/std",
"log/std",
"pallet-assets/std",
"pallet-contracts/std",
"pallet-llm/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
]
Loading

0 comments on commit af5e674

Please sign in to comment.