-
Notifications
You must be signed in to change notification settings - Fork 0
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
(WIP) MFT batch transfers #1
base: master
Are you sure you want to change the base?
Changes from all commits
aeece92
f7f241c
33c3568
2a83336
46f46f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
[build] | ||
rustflags = ["-C", "link-args=-s"] | ||
target = "wasm32-unknown-unknown" | ||
[target.wasm32-unknown-unknown] | ||
rustflags = ["-C", "link-arg=-s"] |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/bin/bash | ||
TARGET="${CARGO_TARGET_DIR:-target}" | ||
set -e | ||
cd "`dirname $0`" | ||
|
||
cargo build --all --target wasm32-unknown-unknown --release | ||
cp $TARGET/wasm32-unknown-unknown/release/defi.wasm ./res/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
cp $TARGET/wasm32-unknown-unknown/release/multi_token.wasm ./res/ | ||
cp $TARGET/wasm32-unknown-unknown/release/approval_receiver.wasm ./res/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[package] | ||
name = "multi-token" | ||
version = "1.1.0" | ||
authors = ["Near Inc <[email protected]>"] | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib", "rlib"] | ||
|
||
[dependencies] | ||
near-sdk = "4.0.0-pre.6" | ||
nep-246 = { path = "../../../" } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; | ||
use near_sdk::collections::{LazyOption}; | ||
use near_sdk::json_types::U128; | ||
use near_sdk::Promise; | ||
use near_sdk::{ | ||
env, near_bindgen, require, AccountId, Balance, BorshStorageKey, PanicOnDefault, PromiseOrValue, | ||
}; | ||
use nep_246::multi_token::metadata::MT_METADATA_SPEC; | ||
use nep_246::multi_token::token::{Approval, Token, TokenId}; | ||
use nep_246::multi_token::{ | ||
core::MultiToken, | ||
metadata::{MtContractMetadata, TokenMetadata}, | ||
}; | ||
|
||
#[near_bindgen] | ||
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)] | ||
pub struct ExampleMTContract { | ||
tokens: MultiToken, | ||
metadata: LazyOption<MtContractMetadata>, | ||
} | ||
|
||
#[derive(BorshSerialize, BorshStorageKey)] | ||
enum StorageKey { | ||
MultiToken, | ||
Metadata, | ||
TokenMetadata, | ||
Enumeration, | ||
Approval, | ||
} | ||
|
||
#[near_bindgen] | ||
impl ExampleMTContract { | ||
#[init] | ||
pub fn new_default_meta(owner_id: AccountId) -> Self { | ||
let metadata = MtContractMetadata { | ||
spec: MT_METADATA_SPEC.to_string(), | ||
name: "Test".to_string(), | ||
symbol: "OMG".to_string(), | ||
icon: None, | ||
base_uri: None, | ||
reference: None, | ||
reference_hash: None, | ||
}; | ||
|
||
Self::new(owner_id, metadata) | ||
} | ||
|
||
#[init] | ||
pub fn new(owner_id: AccountId, metadata: MtContractMetadata) -> Self { | ||
require!(!env::state_exists(), "Already initialized"); | ||
metadata.assert_valid(); | ||
|
||
Self { | ||
tokens: MultiToken::new( | ||
StorageKey::MultiToken, | ||
owner_id, | ||
Some(StorageKey::TokenMetadata), | ||
Some(StorageKey::Enumeration), | ||
Some(StorageKey::Approval), | ||
), | ||
metadata: LazyOption::new(StorageKey::Metadata, Some(&metadata)), | ||
} | ||
} | ||
|
||
#[payable] | ||
pub fn mt_mint( | ||
&mut self, | ||
token_owner_id: AccountId, | ||
token_metadata: TokenMetadata, | ||
amount: Balance, | ||
) -> Token { | ||
// Only the owner of the MFT contract can perform this operation | ||
assert_eq!(env::predecessor_account_id(), self.tokens.owner_id, "Unauthorized: {} != {}", env::predecessor_account_id(), self.tokens.owner_id); | ||
self.tokens.internal_mint(token_owner_id, Some(amount), Some(token_metadata), None) | ||
} | ||
|
||
pub fn register(&mut self, token_id: TokenId, account_id: AccountId) { | ||
self.tokens.internal_register_account(&token_id, &account_id) | ||
} | ||
} | ||
|
||
nep_246::impl_multi_token_core!(ExampleMTContract, tokens); | ||
nep_246::impl_multi_token_approval!(ExampleMTContract, tokens); | ||
nep_246::impl_multi_token_enumeration!(ExampleMTContract, tokens); | ||
|
||
#[cfg(all(test, not(target_arch = "wasm32")))] | ||
mod tests { | ||
use near_sdk::test_utils::{accounts, VMContextBuilder}; | ||
use near_sdk::{testing_env}; | ||
use super::*; | ||
|
||
fn create_token_md(title: String, description: String) -> TokenMetadata { | ||
TokenMetadata { | ||
title: Some(title), | ||
description: Some(description), | ||
media: None, | ||
media_hash: None, | ||
issued_at: Some(String::from("123456")), | ||
expires_at: None, | ||
starts_at: None, | ||
updated_at: None, | ||
extra: None, | ||
reference: None, | ||
reference_hash: None, | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_transfer() { | ||
let mut context = VMContextBuilder::new(); | ||
testing_env!(context | ||
.signer_account_id(accounts(0)) | ||
.predecessor_account_id(accounts(0)) | ||
.build()); | ||
|
||
let mut contract = ExampleMTContract::new_default_meta(accounts(0)); | ||
let token_md = create_token_md("ABC".into(), "Alphabet token".into()); | ||
|
||
let token = contract.mt_mint(accounts(0), token_md.clone(), 1000); | ||
assert_eq!(contract.mt_balance_of(accounts(0), token.token_id.clone()), 1000.into(), "Wrong balance"); | ||
|
||
contract.register(token.token_id.clone(), accounts(1)); | ||
assert_eq!(contract.mt_balance_of(accounts(1), token.token_id.clone()), 0.into(), "Wrong balance"); | ||
|
||
testing_env!(context.attached_deposit(1).build()); | ||
contract.mt_transfer(accounts(1), token.token_id.clone(), 4.into(), None, None); | ||
|
||
assert_eq!(contract.mt_balance_of(accounts(0), token.token_id.clone()).0, 996, "Wrong balance"); | ||
assert_eq!(contract.mt_balance_of(accounts(1), token.token_id.clone()).0, 4, "Wrong balance"); | ||
} | ||
|
||
#[test] | ||
fn test_batch_transfer() { | ||
let mut context = VMContextBuilder::new(); | ||
testing_env!(context | ||
.signer_account_id(accounts(0)) | ||
.predecessor_account_id(accounts(0)) | ||
.build()); | ||
let mut contract = ExampleMTContract::new_default_meta(accounts(0)); | ||
|
||
let quote_token_md = create_token_md("PYC".into(), "Python token".into()); | ||
let base_token_md = create_token_md("ABC".into(), "Alphabet token".into()); | ||
|
||
let quote_token = contract.mt_mint(accounts(0), quote_token_md.clone(), 1000); | ||
let base_token = contract.mt_mint(accounts(0), base_token_md.clone(), 2000); | ||
contract.register(quote_token.token_id.clone(), accounts(1)); | ||
contract.register(base_token.token_id.clone(), accounts(1)); | ||
|
||
testing_env!(context.attached_deposit(1).build()); | ||
|
||
// Perform the transfers | ||
contract.mt_batch_transfer( | ||
accounts(1), | ||
vec![quote_token.token_id.clone(), base_token.token_id.clone()], | ||
vec![4.into(), 600.into()], | ||
None, | ||
None | ||
); | ||
|
||
assert_eq!(contract.mt_balance_of(accounts(0), quote_token.token_id.clone()).0, 996, "Wrong balance"); | ||
assert_eq!(contract.mt_balance_of(accounts(1), quote_token.token_id.clone()).0, 4, "Wrong balance"); | ||
|
||
assert_eq!(contract.mt_balance_of(accounts(0), base_token.token_id.clone()).0, 1400, "Wrong balance"); | ||
assert_eq!(contract.mt_balance_of(accounts(1), base_token.token_id.clone()).0, 600, "Wrong balance"); | ||
} | ||
|
||
#[test] | ||
fn test_transfer_call() { | ||
// How to test a multi-contract call? | ||
let mut context = VMContextBuilder::new(); | ||
testing_env!(context | ||
.signer_account_id(accounts(0)) | ||
.predecessor_account_id(accounts(0)) | ||
.attached_deposit(1) | ||
.build()); | ||
let mut contract = ExampleMTContract::new_default_meta(accounts(0)); | ||
let quote_token_md = create_token_md("ABC".into(), "Alphabet token".into()); | ||
|
||
// alice starts with 1000, bob with 0. | ||
let quote_token = contract.mt_mint(accounts(0), quote_token_md.clone(), 1000); | ||
contract.register(quote_token.token_id.clone(), accounts(1)); | ||
|
||
let _result = contract.mt_transfer_call( | ||
accounts(1), // receiver account | ||
quote_token.token_id.clone(), | ||
100, // amount | ||
None, | ||
String::from("invest"), | ||
); | ||
|
||
|
||
// println!("result: {}", result); | ||
} | ||
|
||
#[test] | ||
fn test_batch_transfer_call() { | ||
|
||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump this latest