Skip to content

Commit

Permalink
fix: fixed icp-price with correct fee to apply
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Feb 16, 2024
1 parent f2aa6b0 commit 29e2099
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 24 deletions.
Binary file removed assets/wasm/xrc.wasm
Binary file not shown.
22 changes: 15 additions & 7 deletions integration-tests/src/client/icrc.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use candid::{Encode, Nat, Principal};
use icrc::{
icrc1::account::Account,
icrc2::{
approve::{ApproveArgs, ApproveError},
transfer_from::{TransferFromArgs, TransferFromError},
},
};
use icrc::icrc1::account::Account;
use icrc::icrc2::allowance::{Allowance, AllowanceArgs};
use icrc::icrc2::approve::{ApproveArgs, ApproveError};
use icrc::icrc2::transfer_from::{TransferFromArgs, TransferFromError};

use crate::TestEnv;

Expand All @@ -30,6 +27,17 @@ impl<'a> IcrcLedgerClient<'a> {
.unwrap()
}

pub fn icrc2_allowance(&self, account: Account, spender: Account) -> Allowance {
self.env
.query(
self.principal,
account.owner,
"icrc2_allowance",
Encode!(&AllowanceArgs { account, spender }).unwrap(),
)
.unwrap()
}

pub fn icrc2_approve(
&self,
caller: Principal,
Expand Down
64 changes: 59 additions & 5 deletions integration-tests/tests/use_case/buy_marketplace_nft.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use did::deferred::{ContractRegistration, ContractType, GenericValue, Seller, ID};
use icrc::icrc1::account::Account;
use integration_tests::actor::{alice, bob, charlie, charlie_account};
use integration_tests::actor::{alice, alice_account, bob, charlie, charlie_account};
use integration_tests::client::{DeferredClient, IcrcLedgerClient, MarketplaceClient};
use integration_tests::TestEnv;
use pretty_assertions::{assert_eq, assert_ne};
Expand Down Expand Up @@ -37,11 +37,11 @@ fn test_should_buy_marketplace_nft_as_non_contract_buyer() {
None
)
.is_ok());
let allowance =
icp_ledger_client.icrc2_allowance(alice_account(), Account::from(env.marketplace_id));
assert_eq!(icp_price, allowance.allowance);

// buy token
let err = marketplace_client
.buy_token(charlie(), &token_to_buy, &charlie_account().subaccount)
.unwrap_err();
println!("{:?}", err);
assert!(marketplace_client
.buy_token(charlie(), &token_to_buy, &charlie_account().subaccount)
.is_ok());
Expand All @@ -56,6 +56,60 @@ fn test_should_buy_marketplace_nft_as_non_contract_buyer() {
assert_eq!(balance_diff, token.picoekoke_reward);
}

#[test]
#[serial_test::serial]
fn test_should_buy_marketplace_nft_as_contract_buyer() {
let env = TestEnv::init();
let contract_id = setup_contract_marketplace(&env);

let deferred_client = DeferredClient::from(&env);
let marketplace_client = MarketplaceClient::from(&env);
let ekoke_ledger_client = IcrcLedgerClient::new(env.ekoke_id, &env);
let icp_ledger_client = IcrcLedgerClient::new(env.icp_ledger_id, &env);

// get initial ekoke balance for charlie
let initial_balance = ekoke_ledger_client.icrc1_balance_of(alice_account());

// get contract by id
let contract = deferred_client.get_contract(&contract_id).unwrap();
let token_to_buy = contract.tokens[0].clone();
// get nft price
let icp_price = marketplace_client
.get_token_price_icp(alice(), &token_to_buy)
.unwrap();
assert_ne!(icp_price, 0);

// approve on icp ledger client a spend for token price to marketplace canister
assert!(icp_ledger_client
.icrc2_approve(
alice(),
Account::from(env.marketplace_id),
icp_price.into(),
alice_account().subaccount
)
.is_ok());

let allowance =
icp_ledger_client.icrc2_allowance(alice_account(), Account::from(env.marketplace_id));
assert_eq!(icp_price, allowance.allowance);

// buy token
assert!(marketplace_client
.buy_token(alice(), &token_to_buy, &alice_account().subaccount)
.is_ok());

// verify token owner is charlie
let token = deferred_client.get_token(&token_to_buy).unwrap().token;
assert!(token.owner.is_none());
// should be burned
assert!(token.is_burned);

// verify alice got the reward
let final_balance = ekoke_ledger_client.icrc1_balance_of(alice_account());
let balance_diff = final_balance - initial_balance;
assert_eq!(balance_diff, token.picoekoke_reward);
}

fn setup_contract_marketplace(env: &TestEnv) -> ID {
let deferred_client = DeferredClient::from(env);

Expand Down
8 changes: 3 additions & 5 deletions integration-tests/tests/use_case/icrc2_spend.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use candid::Nat;
use integration_tests::{
actor::{alice, alice_account, bob_account, charlie, charlie_account},
client::IcrcLedgerClient,
TestEnv,
};
use integration_tests::actor::{alice, alice_account, bob_account, charlie, charlie_account};
use integration_tests::client::IcrcLedgerClient;
use integration_tests::TestEnv;
use serial_test::serial;

#[test]
Expand Down
20 changes: 15 additions & 5 deletions src/marketplace/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ use crate::app::exchange_rate::ExchangeRate;
use crate::client::{DeferredClient, EkokeClient};
use crate::utils::{caller, cycles, id, time};

#[allow(dead_code)]
struct TokenInfoWithPrice {
token_info: TokenInfo,
icp_price_without_interest: u64,
icp_price_with_interest: u64,
icp_fee: u64,
/// Allowance needed to set to the marketplace canister to buy the token
allowance: u64,
interest: u64,
is_caller_contract_buyer: bool,
is_first_sell: bool,
Expand Down Expand Up @@ -101,12 +104,12 @@ impl Marketplace {
Configuration::set_icp_ledger_canister(canister_id);
}

/// Given a token id, returns the price of the token in ICP.
/// Given a token id, returns the price of the token in ICP plus the icp ledger fee, which must be approved to spend.
pub async fn get_token_price_icp(token_id: TokenIdentifier) -> MarketplaceResult<u64> {
// get token info
let token_info = Self::get_token_info_with_price(&token_id).await?;

Ok(token_info.icp_price_with_interest)
Ok(token_info.allowance)
}

/// Buy token with the provided id. The buy process, given the IC price, consits of:
Expand Down Expand Up @@ -153,7 +156,7 @@ impl Marketplace {
}

// check if allowance is enough
if allowance.allowance < info.icp_price_with_interest + info.icp_fee {
if allowance.allowance < info.allowance {
return Err(MarketplaceError::Buy(BuyError::IcpAllowanceNotEnough));
}

Expand Down Expand Up @@ -227,12 +230,19 @@ impl Marketplace {
};
let interest = icp_price_with_interest - icp_price_without_interest;

let allowance = if is_caller_contract_buyer {
icp_price_with_interest + (icp_fee * 2)
} else {
icp_price_without_interest + icp_fee
};

Ok(TokenInfoWithPrice {
is_first_sell: token_info.token.transferred_at.is_none(),
token_info,
icp_price_without_interest,
icp_price_with_interest,
icp_fee,
allowance,
interest,
is_caller_contract_buyer,
})
Expand Down Expand Up @@ -380,7 +390,7 @@ mod test {
let icp_price = Marketplace::get_token_price_icp(TokenIdentifier::from(2_u64))
.await
.unwrap();
assert_eq!(icp_price, 1353013530); // with interest
assert_eq!(icp_price, 1353013530 + (10_000 * 2)); // with interest
}

#[tokio::test]
Expand All @@ -389,7 +399,7 @@ mod test {
let icp_price = Marketplace::get_token_price_icp(TokenIdentifier::from(1_u64))
.await
.unwrap();
assert_eq!(icp_price, 1230012300);
assert_eq!(icp_price, 1230012300 + 10_000);
}

#[tokio::test]
Expand Down
4 changes: 2 additions & 2 deletions src/marketplace/src/client/ekoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ impl EkokeClient {
}
#[cfg(target_arch = "wasm32")]
{
let result: (EkokeResult<LiquidityPoolAccounts>,) =
let result: (LiquidityPoolAccounts,) =
ic_cdk::api::call::call(self.ekoke_canister, "liquidity_pool_accounts", ())
.await
.map_err(|(code, err)| MarketplaceError::CanisterCall(code, err))?;
Ok(result.0?)
Ok(result.0)
}
}

Expand Down

0 comments on commit 29e2099

Please sign in to comment.