Skip to content

Commit

Permalink
Add several bids test case
Browse files Browse the repository at this point in the history
  • Loading branch information
DOBEN committed Nov 28, 2023
1 parent e39fd36 commit 09748fd
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 40 deletions.
24 changes: 4 additions & 20 deletions examples/sponsored-tx-enabled-auction/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,24 +212,8 @@ fn view_item_state(ctx: &ReceiveContext, host: &Host<State>) -> ReceiveResult<It
Ok(item)
}

#[derive(Debug, Serialize, SchemaType)]
pub struct TestOnReceivingCis2Params<T, A> {
/// The ID of the token received.
pub token_id: T,
/// The amount of tokens received.
pub amount: A,
/// The previous owner of the tokens.
pub from: Address,
/// Some extra information which where sent as part of the transfer.
pub data: AdditionalDataItem,
}

/// Additional information to include with a transfer.
#[derive(Debug, Serialize, Clone, SchemaType)]
#[concordium(transparent)]
pub struct AdditionalDataItem(#[concordium(size_length = 2)] Vec<u8>);

#[derive(Debug, Deserial, Serial, Clone, SchemaType)]
#[concordium(transparent)]
pub struct AdditionalDataIndex {
pub item_index: u16,
}
Expand All @@ -239,12 +223,12 @@ pub struct AdditionalDataIndex {
contract = "sponsored_tx_enabled_auction",
name = "bid",
mutable,
parameter = "TestOnReceivingCis2Params<ContractTokenId, ContractTokenAmount>",
parameter = "OnReceivingCis2Params<ContractTokenId, ContractTokenAmount>",
error = "Error"
)]
fn auction_bid(ctx: &ReceiveContext, host: &mut Host<State>) -> ReceiveResult<()> {
// Parse the parameter.
let params: TestOnReceivingCis2Params<ContractTokenId, ContractTokenAmount> =
let params: OnReceivingCis2Params<ContractTokenId, ContractTokenAmount> =
ctx.parameter_cursor().get()?;

// Ensure the sender is the cis2_token_contract.
Expand All @@ -254,7 +238,7 @@ fn auction_bid(ctx: &ReceiveContext, host: &mut Host<State>) -> ReceiveResult<()
bail!(Error::NotTokenContract.into())
};

let additional_data_index: AdditionalDataIndex = from_bytes(&params.data.0)?;
let additional_data_index: AdditionalDataIndex = from_bytes(params.data.as_ref())?;

let cis2_contract = host.state().cis2_contract;

Expand Down
252 changes: 232 additions & 20 deletions examples/sponsored-tx-enabled-auction/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,8 @@ const DUMMY_SIGNATURE: SignatureEd25519 = SignatureEd25519([

#[test]
fn test_add_item() {
let (
mut chain,
_keypairs_alice,
_keypairs_bob,
auction_contract_address,
_token_contract_address,
) = initialize_chain_and_auction();
let (mut chain, _keypairs_alice, auction_contract_address, _token_contract_address) =
initialize_chain_and_auction();

// Create the InitParameter.
let parameter = AddItemParameter {
Expand Down Expand Up @@ -125,13 +120,8 @@ fn test_add_item() {

#[test]
fn full_auction_flow_with_cis3_permit_function() {
let (
mut chain,
keypairs_alice,
_keypairs_bob,
auction_contract_address,
token_contract_address,
) = initialize_chain_and_auction();
let (mut chain, keypairs_alice, auction_contract_address, token_contract_address) =
initialize_chain_and_auction();

// Create the InitParameter.
let parameter = AddItemParameter {
Expand Down Expand Up @@ -300,9 +290,233 @@ fn full_auction_flow_with_cis3_permit_function() {
assert_eq!(item_state.auction_state, AuctionState::Sold(ALICE));
}

#[test]
fn full_auction_flow_with_several_bids() {
let (mut chain, keypairs_alice, auction_contract_address, token_contract_address) =
initialize_chain_and_auction();

// Create the InitParameter.
let parameter = AddItemParameter {
name: "MyItem".to_string(),
end: Timestamp::from_timestamp_millis(1000),
start: Timestamp::from_timestamp_millis(5000),
token_id: TokenIdU8(1),
minimum_bid: TokenAmountU64(0),
};

let _update = chain
.contract_update(
SIGNER,
ALICE,
Address::Account(ALICE),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::from_ccd(0),
address: auction_contract_address,
receive_name: OwnedReceiveName::new_unchecked(
"sponsored_tx_enabled_auction.addItem".to_string(),
),
message: OwnedParameter::from_serial(&parameter).expect("Serialize parameter"),
},
)
.expect("Should be able to add Item");

let parameter = cis2_multi::MintParams {
owner: concordium_smart_contract_testing::Address::Account(ALICE),
metadata_url: MetadataUrl {
url: "https://some.example/token/0".to_string(),
hash: None,
},
token_id: concordium_cis2::TokenIdU8(1u8),
};

let _update = chain
.contract_update(
SIGNER,
ALICE,
Address::Account(ALICE),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::from_ccd(0),
address: token_contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis2_multi.mint".to_string()),
message: OwnedParameter::from_serial(&parameter).expect("Serialize parameter"),
},
)
.expect("Should be able to finalize");

let additional_data = AdditionalDataIndex {
item_index: 0u16,
};

// Check balances in state.
let balance_of_alice_and_auction_contract =
get_balances(&chain, auction_contract_address, token_contract_address);

assert_eq!(balance_of_alice_and_auction_contract.0, [TokenAmountU64(100), TokenAmountU64(0)]);

// Create input parameters for the `permit` transfer function.
let transfer = concordium_cis2::Transfer {
from: ALICE_ADDR,
to: Receiver::Contract(
auction_contract_address,
OwnedEntrypointName::new_unchecked("bid".to_string()),
),
token_id: TokenIdU8(1),
amount: TokenAmountU64(1),
data: AdditionalData::from(to_bytes(&additional_data)),
};
let payload = TransferParams::from(vec![transfer]);

// The `viewMessageHash` function uses the same input parameter `PermitParam` as
// the `permit` function. The `PermitParam` type includes a `signature` and
// a `signer`. Because these two values (`signature` and `signer`) are not
// read in the `viewMessageHash` function, any value can be used and we choose
// to use `DUMMY_SIGNATURE` and `ALICE` in the test case below.
let signature_map = BTreeMap::from([(0u8, CredentialSignatures {
sigs: BTreeMap::from([(0u8, concordium_std::Signature::Ed25519(DUMMY_SIGNATURE))]),
})]);

let mut permit_transfer_param = PermitParam {
signature: AccountSignatures {
sigs: signature_map,
},
signer: ALICE,
message: PermitMessage {
timestamp: Timestamp::from_timestamp_millis(10_000_000_000),
contract_address: ContractAddress::new(0, 0),
entry_point: OwnedEntrypointName::new_unchecked("transfer".into()),
nonce: 0,
payload: to_bytes(&payload),
},
};

// Get the message hash to be signed.
let invoke = chain
.contract_invoke(BOB, BOB_ADDR, Energy::from(10000), UpdateContractPayload {
amount: Amount::zero(),
address: token_contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis2_multi.viewMessageHash".to_string()),
message: OwnedParameter::from_serial(&permit_transfer_param)
.expect("Should be a valid inut parameter"),
})
.expect("Should be able to query viewMessageHash");

let message_hash: HashSha2256 =
from_bytes(&invoke.return_value).expect("Should return a valid result");

permit_transfer_param.signature = keypairs_alice.sign_message(&to_bytes(&message_hash));

// Transfer token with the permit function.
let _update = chain
.contract_update(
Signer::with_one_key(),
BOB,
BOB_ADDR,
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: token_contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis2_multi.permit".to_string()),
message: OwnedParameter::from_serial(&permit_transfer_param)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to transfer token with permit");

// Check balances in state.
let balance_of_alice_and_auction_contract =
get_balances(&chain, auction_contract_address, token_contract_address);

assert_eq!(balance_of_alice_and_auction_contract.0, [TokenAmountU64(99), TokenAmountU64(1)]);

let parameter = cis2_multi::MintParams {
owner: concordium_smart_contract_testing::Address::Account(BOB),
metadata_url: MetadataUrl {
url: "https://some.example/token/0".to_string(),
hash: None,
},
token_id: concordium_cis2::TokenIdU8(1u8),
};

let _update = chain
.contract_update(
SIGNER,
ALICE,
Address::Account(BOB),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::from_ccd(0),
address: token_contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis2_multi.mint".to_string()),
message: OwnedParameter::from_serial(&parameter).expect("Serialize parameter"),
},
)
.expect("Should be able to finalize");

// Transfer one token from Alice to bid function in auction.
let transfer_params = TransferParams::from(vec![concordium_cis2::Transfer {
from: BOB_ADDR,
to: Receiver::Contract(
auction_contract_address,
OwnedEntrypointName::new_unchecked("bid".to_string()),
),
token_id: TokenIdU8(1),
amount: TokenAmountU64(2),
data: AdditionalData::from(to_bytes(&additional_data)),
}]);

let _update = chain
.contract_update(SIGNER, BOB, BOB_ADDR, Energy::from(10000), UpdateContractPayload {
amount: Amount::zero(),
receive_name: OwnedReceiveName::new_unchecked("cis2_multi.transfer".to_string()),
address: token_contract_address,
message: OwnedParameter::from_serial(&transfer_params).expect("Transfer params"),
})
.expect("Transfer tokens");

// Check that ALICE has been refunded her initial bid and the auction contract
// recieved the 2 tokens from BOB.
let balance_of_alice_and_auction_contract =
get_balances(&chain, auction_contract_address, token_contract_address);

assert_eq!(balance_of_alice_and_auction_contract.0, [TokenAmountU64(100), TokenAmountU64(2)]);

// Invoke the view entrypoint and check that the tokens are owned by Alice.
let item_state = view_item_state(&chain, auction_contract_address);

// Check that item is not sold yet.
assert_eq!(item_state.auction_state, AuctionState::NotSoldYet);

// Increment the chain time by 100000 milliseconds.
chain.tick_block_time(Duration::from_millis(100000)).expect("Increment chain time");

let _update = chain
.contract_update(
SIGNER,
ALICE,
Address::Account(ALICE),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::from_ccd(0),
address: auction_contract_address,
receive_name: OwnedReceiveName::new_unchecked(
"sponsored_tx_enabled_auction.finalize".to_string(),
),
message: OwnedParameter::from_serial(&0u16).expect("Serialize parameter"),
},
)
.expect("Should be able to finalize");

// Invoke the view entrypoint and check that the tokens are owned by Alice.
let item_state = view_item_state(&chain, auction_contract_address);

assert_eq!(item_state.auction_state, AuctionState::Sold(BOB));
}

#[test]
fn full_auction_flow_with_cis3_transfer_function() {
let (mut chain, _keypair_alice, _keypair_bob, auction_contract_address, token_contract_address) =
let (mut chain, _keypair_alice, auction_contract_address, token_contract_address) =
initialize_chain_and_auction();

// Create the InitParameter.
Expand Down Expand Up @@ -707,8 +921,7 @@ fn get_balances(
/// Carol is the owner of the auction, which ends at `1000` milliseconds after
/// the unix epoch. The 'microCCD per euro' exchange rate is set to `1_000_000`,
/// so 1 CCD = 1 euro.
fn initialize_chain_and_auction(
) -> (Chain, AccountKeys, AccountKeys, ContractAddress, ContractAddress) {
fn initialize_chain_and_auction() -> (Chain, AccountKeys, ContractAddress, ContractAddress) {
let mut chain = Chain::builder()
.micro_ccd_per_euro(
ExchangeRate::new(1_000_000, 1).expect("Exchange rate is in valid range"),
Expand All @@ -719,7 +932,6 @@ fn initialize_chain_and_auction(
let rng = &mut rand::thread_rng();

let keypairs_alice = AccountKeys::singleton(rng);
let keypairs_bob = AccountKeys::singleton(rng);

let balance = AccountBalance {
total: ACC_INITIAL_BALANCE,
Expand All @@ -729,7 +941,7 @@ fn initialize_chain_and_auction(

// Create some accounts accounts on the chain.
chain.create_account(Account::new_with_keys(ALICE, balance, (&keypairs_alice).into()));
chain.create_account(Account::new_with_keys(BOB, balance, (&keypairs_bob).into()));
chain.create_account(Account::new(BOB, ACC_INITIAL_BALANCE));
chain.create_account(Account::new(BOB, ACC_INITIAL_BALANCE));
chain.create_account(Account::new(CAROL, ACC_INITIAL_BALANCE));
chain.create_account(Account::new(DAVE, ACC_INITIAL_BALANCE));
Expand Down Expand Up @@ -771,5 +983,5 @@ fn initialize_chain_and_auction(
})
.expect("Initialize auction");

(chain, keypairs_alice, keypairs_bob, init_auction.contract_address, token.contract_address)
(chain, keypairs_alice, init_auction.contract_address, token.contract_address)
}

0 comments on commit 09748fd

Please sign in to comment.