Skip to content

Commit

Permalink
solution2
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Huang committed Sep 2, 2022
1 parent 51c5404 commit 9054fe9
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 167 deletions.
203 changes: 88 additions & 115 deletions amm-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
use near_contract_standards::fungible_token::receiver::FungibleTokenReceiver;
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::{env, ext_contract, log, near_bindgen, require, AccountId, Balance, PanicOnDefault};

const A_BALANCE: u128 = 40_000_000_000_000_000_000_000;
const B_BALANCE: u128 = 300_000_000_000_000_000_000;
use near_sdk::json_types::U128;
use near_sdk::{
assert_self, env, ext_contract, log, near_bindgen, require, AccountId, Balance, PanicOnDefault,
Promise, PromiseOrValue, PromiseResult,
};

#[ext_contract(ext_token)]
trait ExtToken {
fn get_info(&self) -> (String, u8);
fn register_amm(&mut self, sender_id: AccountId, amount: Balance);
fn transfer_from(&mut self, sender_id: AccountId, receiver_id: AccountId, amount: Balance);
fn ft_transfer(&mut self, receiver_id: AccountId, amount: U128);
}

#[ext_contract(ext_self)]
trait ExtSelf {
fn callback_get_info(&mut self, contract_id: AccountId, #[callback] val: (String, u8));
fn callback_ft_deposit(
&mut self,
a_balance_after: Balance,
b_balance_after: Balance,
contract_id: AccountId,
receiver_id: AccountId,
amount: Balance,
);
fn callback_update_balances(&mut self, a_balance_after: Balance, b_balance_after: Balance);
}

Expand All @@ -48,10 +41,8 @@ pub struct Contract {

#[near_bindgen]
impl Contract {
/// Initialization method:
/// Input are the address of the contract owner and the addresses of two tokens (hereinafter token A and token B).
/// requests and stores the metadata of tokens (name, decimals) and
/// Creates wallets for tokens А & В.
/// requests and stores the metadata of tokens (name, decimals)
#[init]
pub fn new(owner_id: AccountId, a_contract_id: AccountId, b_contract_id: AccountId) -> Self {
require!(!env::state_exists(), "The contract has been initialized");
Expand All @@ -63,20 +54,17 @@ impl Contract {
ext_token::ext(b_contract_id.clone()).get_info().then(
ext_self::ext(env::current_account_id()).callback_get_info(b_contract_id.clone()),
);
// Creates wallets for tokens А & В.
ext_token::ext(a_contract_id.clone()).register_amm(owner_id.clone(), A_BALANCE);
ext_token::ext(b_contract_id.clone()).register_amm(owner_id.clone(), B_BALANCE);

Self {
owner_id,
ratio: 0,
a_balance: A_BALANCE,
a_balance: 0,
a_meta: TokenMeta {
account_id: a_contract_id,
ticker: "".into(),
decimal: 1,
},
b_balance: B_BALANCE,
b_balance: 0,
b_meta: TokenMeta {
account_id: b_contract_id,
ticker: "".into(),
Expand All @@ -85,11 +73,26 @@ impl Contract {
}
}

pub fn callback_update_balances(
&mut self,
a_balance_after: Balance,
b_balance_after: Balance,
) -> PromiseOrValue<U128> {
assert_self();

match env::promise_result(0) {
PromiseResult::NotReady => env::abort(),
PromiseResult::Successful(_) => {
self.update_balances(a_balance_after, b_balance_after);
PromiseOrValue::Value(0.into())
}
PromiseResult::Failed => env::panic_str("fail!"),
}
}

pub fn callback_get_info(&mut self, contract_id: AccountId, #[callback] val: (String, u8)) {
require!(
env::predecessor_account_id() == env::current_account_id(),
"only support in self"
);
assert_self();

log!("Fill additional info for {}", val.0);
if contract_id == self.a_meta.account_id {
self.a_meta.ticker = val.0;
Expand Down Expand Up @@ -127,127 +130,97 @@ impl Contract {
self.ratio
}

fn calc_ratio(&mut self) {
pub fn calc_ratio(&mut self) {
let a_num = self.a_balance / 10_u128.pow(self.a_meta.decimal);
let b_num = self.b_balance / 10_u128.pow(self.b_meta.decimal);
//X * Y = K , K is some constant value
self.ratio = a_num * b_num;
}

/// The user can transfer a certain number of tokens A to the contract account and
/// in return must receive a certain number of tokens B (similarly in the other direction).
/// The contract supports a certain ratio of tokens A and B. X * Y = K
/// K is some constant value, X and Y are the number of tokens A and B respectively.
#[payable]
pub fn deposit_a(&mut self, amount: Balance) {
let sender_id = env::predecessor_account_id();
fn deposit_a(&mut self, sender_id: AccountId, a_amount: Balance) -> Promise {
let decimal = 10_u128.pow(self.a_meta.decimal);
let a_amount = amount * decimal;
let a_balance_after = a_amount + self.a_balance;
let b_balance_after =
self.ratio / (a_balance_after / decimal) * 10_u128.pow(self.b_meta.decimal);
let b_balance_after = ((self.ratio * decimal / a_balance_after) as f64
* 10_u128.pow(self.b_meta.decimal) as f64) as u128;
let b_amount = self.b_balance - b_balance_after;
let next_contract = self.b_meta.account_id.clone();
ext_token::ext(self.a_meta.account_id.clone())
.transfer_from(sender_id.clone(), env::current_account_id(), a_amount)

ext_token::ext(next_contract)
.with_attached_deposit(1)
.ft_transfer(sender_id, b_amount.into())
.then(
ext_self::ext(env::current_account_id()).callback_ft_deposit(
a_balance_after,
b_balance_after,
next_contract,
sender_id,
b_amount,
),
);
ext_self::ext(env::current_account_id())
.callback_update_balances(a_balance_after, b_balance_after),
)
}

/// The owner of the contract can transfer a certain amount of tokens A or B to the contract account,
/// thereby changing the ratio K.
#[payable]
pub fn deposit_a_by_owner(&mut self, amount: Balance) {
require!(
env::predecessor_account_id() == self.owner_id,
"only support to call by itself"
);
let a_amount = amount * 10_u128.pow(self.a_meta.decimal);
fn deposit_a_by_owner(&mut self, a_amount: Balance) {
let a_balance_after = a_amount + self.a_balance;
let b_balance_after = self.b_balance;
ext_token::ext(self.a_meta.account_id.clone())
.transfer_from(self.owner_id.clone(), env::current_account_id(), a_amount)
.then(
ext_self::ext(env::current_account_id())
.callback_update_balances(a_balance_after, b_balance_after),
);

self.update_balances(a_balance_after, b_balance_after);
}

/// in the opposite direction
#[payable]
pub fn deposit_b(&mut self, amount: Balance) {
let sender_id = env::predecessor_account_id();
fn deposit_b(&mut self, sender_id: AccountId, b_amount: Balance) -> Promise {
let decimal = 10_u128.pow(self.b_meta.decimal);
let b_amount = amount * decimal;
let b_balance_after = b_amount + self.b_balance;
let a_balance_after =
self.ratio / (b_balance_after / decimal) * 10_u128.pow(self.a_meta.decimal);
let a_balance_after = ((self.ratio * decimal / b_balance_after) as f64
* 10_u128.pow(self.a_meta.decimal) as f64) as u128;
let a_amount = self.a_balance - a_balance_after;
let next_contract = self.a_meta.account_id.clone();
ext_token::ext(self.b_meta.account_id.clone())
.transfer_from(sender_id.clone(), env::current_account_id(), b_amount)
.then(
ext_self::ext(env::current_account_id()).callback_ft_deposit(
a_balance_after,
b_balance_after,
next_contract,
sender_id,
a_amount,
),
);
}

#[payable]
pub fn deposit_b_by_owner(&mut self, amount: Balance) {
require!(
env::predecessor_account_id() == self.owner_id,
"only support to call by itself"
);
let b_amount = amount * 10_u128.pow(self.b_meta.decimal);
let b_balance_after = b_amount + self.b_balance;
let a_balance_after = self.a_balance;
ext_token::ext(self.b_meta.account_id.clone())
.transfer_from(self.owner_id.clone(), env::current_account_id(), b_amount)
ext_token::ext(next_contract)
.with_attached_deposit(1)
.ft_transfer(sender_id, a_amount.into())
.then(
ext_self::ext(env::current_account_id())
.callback_update_balances(a_balance_after, b_balance_after),
);
)
}

pub fn callback_ft_deposit(
&mut self,
a_balance_after: Balance,
b_balance_after: Balance,
contract_id: AccountId,
receiver_id: AccountId,
amount: Balance,
) {
require!(
env::predecessor_account_id() == env::current_account_id(),
"only support to call by itself"
);
ext_token::ext(contract_id)
.transfer_from(env::current_account_id(), receiver_id, amount)
.then(
ext_self::ext(env::current_account_id())
.callback_update_balances(a_balance_after, b_balance_after),
);
fn deposit_b_by_owner(&mut self, b_amount: Balance) {
let b_balance_after = b_amount + self.b_balance;
let a_balance_after = self.a_balance;

self.update_balances(a_balance_after, b_balance_after);
}

pub fn callback_update_balances(&mut self, a_balance_after: Balance, b_balance_after: Balance) {
require!(
env::predecessor_account_id() == env::current_account_id(),
"only support to call by itself"
);
fn update_balances(&mut self, a_balance_after: Balance, b_balance_after: Balance) {
self.a_balance = a_balance_after;
self.b_balance = b_balance_after;
self.calc_ratio();
}
}

#[near_bindgen]
impl FungibleTokenReceiver for Contract {
/// The user can transfer a certain number of tokens A to the contract account and
/// in return must receive a certain number of tokens B (similarly in the other direction).
/// The contract supports a certain ratio of tokens A and B. X * Y = K
/// K is some constant value, X and Y are the number of tokens A and B respectively.
/// The owner of the contract can transfer a certain amount of tokens A or B to the contract account,
/// thereby changing the ratio K.
fn ft_on_transfer(
&mut self,
sender_id: AccountId,
amount: U128,
msg: String,
) -> PromiseOrValue<U128> {
let _ = msg;
let predecessor_id = env::predecessor_account_id();
if predecessor_id == self.a_meta.account_id && sender_id != self.owner_id {
self.deposit_a(sender_id, amount.into()).into()
} else if predecessor_id == self.a_meta.account_id && sender_id == self.owner_id {
self.deposit_a_by_owner(amount.into());
PromiseOrValue::Value(0.into())
} else if predecessor_id == self.b_meta.account_id && sender_id != self.owner_id {
self.deposit_b(sender_id, amount.into()).into()
} else if predecessor_id == self.b_meta.account_id && sender_id == self.owner_id {
self.deposit_b_by_owner(amount.into());
PromiseOrValue::Value(0.into())
} else {
env::panic_str("invalid call");
}
}
}
2 changes: 1 addition & 1 deletion near-sdk-rs
Submodule near-sdk-rs updated 151 files
Binary file modified res/amm_contract.wasm
Binary file not shown.
46 changes: 35 additions & 11 deletions res/deploy.sh
Original file line number Diff line number Diff line change
@@ -1,43 +1,67 @@
owner_id=geek.testnet
a_id=a.$owner_id
b_id=b.$owner_id
amm_id=z.$owner_id
sim_id=b.$owner_id
amm_id=amm.$owner_id
sim_id=sim.$owner_id

#40000
amm_a_balance=(40000000000000000000000)
#300000
amm_b_balance=( 300000000000000000000)
#1000
sim_a_balance=( 1000000000000000000000)
#111
sim_a_exchange=( 111000000000000000)

near="near --nodeUrl https://rpc.testnet.near.org"

$near delete $a_id $owner_id
$near delete $b_id $owner_id
$near delete $amm_id $owner_id
$near delete $sim_id $owner_id
$near create-account $a_id --masterAccount $owner_id
$near create-account $b_id --masterAccount $owner_id
$near create-account $amm_id --masterAccount $owner_id
$near create-account $sim_id --masterAccount $owner_id
$near deploy $a_id --wasmFile="./token_contract.wasm"
$near deploy $b_id --wasmFile="./token_contract.wasm"
$near deploy $amm_id --wasmFile="./amm_contract.wasm"

$near call $a_id new '{"owner_id":"'$owner_id'", "name":"A Token Contract", "symbol":"A", "total_supply":1000000000000, "decimals": 18}' --accountId=$owner_id
$near call $b_id new '{"owner_id":"'$owner_id'", "name":"B Token Contract", "symbol":"B", "total_supply":20000000000000, "decimals": 15}' --accountId=$owner_id
$near call $amm_id new '{"owner_id":"'$owner_id'", "a_contract_id":"'$a_id'", "b_contract_id":"'$b_id'"}' --accountId=$owner_id --gas=55000000000000

$near call $a_id storage_deposit '{"account_id": "'$amm_id'"}' --accountId=$owner_id --deposit=1
$near call $b_id storage_deposit '{"account_id": "'$amm_id'"}' --accountId=$owner_id --deposit=1
$near call $a_id storage_deposit '{"account_id": "'$sim_id'"}' --accountId=$owner_id --deposit=1
$near call $b_id storage_deposit '{"account_id": "'$sim_id'"}' --accountId=$owner_id --deposit=1

$near call $a_id ft_transfer_call '{"receiver_id": "'$amm_id'","amount":"'$amm_a_balance'","msg":""}' --accountId=$owner_id --deposit=0.000000000000000000000001 --gas=55000000000000
$near call $b_id ft_transfer_call '{"receiver_id": "'$amm_id'","amount":"'$amm_b_balance'","msg":""}' --accountId=$owner_id --deposit=0.000000000000000000000001 --gas=55000000000000
$near call $a_id ft_transfer '{"receiver_id": "'$sim_id'","amount":"'$sim_a_balance'"}' --accountId=$owner_id --deposit=0.000000000000000000000001 --gas=55000000000000

#1000
$near view $a_id ft_balance_of '{"account_id": "'$sim_id'"}'
#0
$near view $b_id ft_balance_of '{"account_id": "'$sim_id'"}'
#40000
$near view $a_id ft_balance_of '{"account_id": "'$amm_id'"}'
#300000
$near view $b_id ft_balance_of '{"account_id": "'$amm_id'"}'
$near view $amm_id get_info
#12000000000
$near view $amm_id get_ratio

$near call $a_id ft_transfer_call '{"receiver_id": "'$amm_id'","amount":"'$sim_a_exchange'","msg":""}' --accountId=$sim_id --deposit=0.000000000000000000000001 --gas=55000000000000

$near call $a_id storage_deposit '{"account_id": "'$sim_id'"}' --accountId=$owner_id --deposit=1
#1000
$near call $a_id ft_transfer '{"receiver_id": "'$sim_id'","amount":"1000000000000000000000"}' --accountId=$owner_id --deposit=0.000000000000000000000001
$near view $a_id ft_balance_of '{"account_id": "'$sim_id'"}'
$near call $amm_id deposit_a '{"amount":111}' --accountId=$sim_id --gas=55000000000000
#1000-111=889
$near view $a_id ft_balance_of '{"account_id": "'$sim_id'"}'
#x
$near view $b_id ft_balance_of '{"account_id": "'$sim_id'"}'
#40000+111=40111
$near view $a_id ft_balance_of '{"account_id": "'$amm_id'"}'
#300000-x
$near view $b_id ft_balance_of '{"account_id": "'$amm_id'"}'
$near view $amm_id get_info
#12000000000
$near view $amm_id get_ratio

$near call $amm_id deposit_b_by_owner '{"amount":34321}' --accountId=$owner_id --gas=55000000000000
$near view $amm_id get_info
$near view $amm_id get_ratio
Binary file modified res/token_contract.wasm
Binary file not shown.
Loading

0 comments on commit 9054fe9

Please sign in to comment.