Skip to content

Commit

Permalink
Add flow with update operator signature
Browse files Browse the repository at this point in the history
  • Loading branch information
DOBEN authored and abizjak committed Jul 15, 2023
1 parent ae00b87 commit 965754a
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 36 deletions.
2 changes: 1 addition & 1 deletion concordium-std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ getrandom = { version = "0.2", features = ["custom"], optional = true }

[dependencies.concordium-contracts-common]
path = "../../../LocalTestingLibrary/concordium-smart-contract-tools/concordium-base/concordium-contracts-common/concordium-contracts-common"
version = "7.1"
version = "7"
default-features = false
features = ["smart-contract"]

Expand Down
264 changes: 229 additions & 35 deletions examples/cis3-nft-sponsored-txs/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
//! contract. To run them, use `cargo test`.
use cis3_nft_sponsored_txs::{MintParams, PermitMessage, PermitParam};
use concordium_cis2::{TokenIdU32, *};
use concordium_smart_contract_testing::{
AccountAccessStructure, AccountBalance, AccountThreshold, CredentialIndex,
CredentialPublicKeys, KeyIndex, SignatureThreshold, VerifyKey, *,
};
use concordium_smart_contract_testing::*;
use concordium_std::{AccountSignatures, CredentialSignatures, SignatureEd25519, Timestamp};
use std::collections::BTreeMap;

const ACC_ADDR_OWNER: AccountAddress = AccountAddress([0u8; 32]);
const ADDR_OWNER: Address = Address::Account(ACC_ADDR_OWNER);
const ACC_ADDR_OTHER: AccountAddress = AccountAddress([1u8; 32]);
const ADDR_OTHER: Address = Address::Account(ACC_ADDR_OTHER);
const ACC_INITIAL_BALANCE: Amount = Amount::from_ccd(1000);
Expand All @@ -29,11 +27,20 @@ const SIGNATURE_TRANSFER: SignatureEd25519 = SignatureEd25519([
181, 11,
]);

const SIGNATURE_UPDATE_OPERATOR: SignatureEd25519 = SignatureEd25519([
50, 83, 36, 119, 75, 223, 109, 182, 152, 68, 46, 46, 249, 11, 169, 109, 51, 211, 47, 56, 60,
155, 62, 59, 70, 8, 107, 72, 147, 141, 226, 153, 43, 234, 82, 164, 168, 43, 202, 244, 213, 95,
101, 101, 155, 226, 130, 77, 47, 243, 161, 219, 100, 208, 106, 109, 102, 189, 171, 159, 22,
179, 148, 0,
]);

type ContractTokenAmount = TokenAmountU8;

/// A helper method for setting up:
/// - The chain,
/// - The two accounts `ACC_ADDR_OWNER` and `ACC_ADDR_OTHER`, both with
/// `ACC_INITIAL_BALANCE` CCD. `ACC_ADDR_OTHER` will be set up with valid public
/// keys so it can generate signatures.
/// `ACC_INITIAL_BALANCE` CCD. `ACC_ADDR_OTHER` will be set up with valid
/// public keys so it can generate signatures.
/// - The deployed and initialized contract.
fn setup_chain_and_contract() -> (Chain, ContractInitSuccess) {
let mut chain = Chain::new();
Expand Down Expand Up @@ -114,8 +121,6 @@ fn test_init() {
/// Permit transfer function.
#[test]
fn test_permit_transfer() {
type ContractTokenAmount = TokenAmountU8;

let (mut chain, initialization) = setup_chain_and_contract();

// Owner of the newly minted token.
Expand All @@ -124,21 +129,56 @@ fn test_permit_transfer() {
};

// Mint token.
let update = chain.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.mint".to_string()),
message: OwnedParameter::from_serial(&mint_param)
.expect("Should be a valid inut parameter"),
},
);
let update = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.mint".to_string()),
message: OwnedParameter::from_serial(&mint_param)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to mint token");

// Check balances in state.
let balance_of_query = BalanceOfQuery {
token_id: TOKEN_1,
address: ADDR_OWNER,
};
let balance_of_query2 = BalanceOfQuery {
token_id: TOKEN_1,
address: ADDR_OTHER,
};

assert!(update.is_ok());
let balance_of_query_vector = BalanceOfQueryParams {
queries: vec![balance_of_query, balance_of_query2],
};

let update = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.balanceOf".to_string()),
message: OwnedParameter::from_serial(&balance_of_query_vector)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to balanceOf");

let balance_of: BalanceOfQueryResponse<ContractTokenAmount> =
from_bytes(&update.return_value).expect("View should always return a valid result");

assert_eq!(balance_of.0, [TokenAmountU8(0), TokenAmountU8(1)]);

let transfer = concordium_cis2::Transfer {
from: ADDR_OTHER,
Expand Down Expand Up @@ -175,19 +215,173 @@ fn test_permit_transfer() {
};

// Transfer token with the permit function.
let update = chain.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.permit".to_string()),
message: OwnedParameter::from_serial(&permit_transfer_param)
.expect("Should be a valid inut parameter"),
let _ = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.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_query = BalanceOfQuery {
token_id: TOKEN_1,
address: ADDR_OWNER,
};
let balance_of_query2 = BalanceOfQuery {
token_id: TOKEN_1,
address: ADDR_OTHER,
};

let balance_of_query_vector = BalanceOfQueryParams {
queries: vec![balance_of_query, balance_of_query2],
};

let update = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.balanceOf".to_string()),
message: OwnedParameter::from_serial(&balance_of_query_vector)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to balanceOf");

let balance_of: BalanceOfQueryResponse<ContractTokenAmount> =
from_bytes(&update.return_value).expect("View should always return a valid result");

assert_eq!(balance_of.0, [TokenAmountU8(1), TokenAmountU8(0)]);
}

/// Permit update operator function.
#[test]
fn test_update_operator() {
let (mut chain, initialization) = setup_chain_and_contract();

// Check operator in state
let operator_of_query = OperatorOfQuery {
address: ADDR_OWNER,
owner: ADDR_OTHER,
};

let operator_of_query_vector = OperatorOfQueryParams {
queries: vec![operator_of_query],
};

// Check operator in state
let update = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.operatorOf".to_string()),
message: OwnedParameter::from_serial(&operator_of_query_vector)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to query operatorOf");

let is_operator_of: OperatorOfQueryResponse =
from_bytes(&update.return_value).expect("View should always return a valid result");

assert_eq!(is_operator_of.0, [false]);

// Create input parematers for the `permit` updateOperator function.
let update_operator = UpdateOperator {
update: OperatorUpdate::Add,
operator: ADDR_OWNER,
};
let payload = UpdateOperatorParams(vec![update_operator]);

let mut inner_signature_map = BTreeMap::new();
inner_signature_map.insert(0u8, concordium_std::Signature::Ed25519(SIGNATURE_UPDATE_OPERATOR));

let mut signature_map = BTreeMap::new();
signature_map.insert(0u8, CredentialSignatures {
sigs: inner_signature_map,
});

let permit_update_operator_param = PermitParam {
signature: AccountSignatures {
sigs: signature_map,
},
);
signer: ACC_ADDR_OTHER,
message: PermitMessage {
timestamp: Timestamp::from_timestamp_millis(10000000000),
contract_address: ContractAddress {
index: 0,
subindex: 0,
},
entry_point: OwnedEntrypointName::new_unchecked("updateOperator".into()),
nonce: 0,
payload: to_bytes(&payload),
},
};

// Update operator with the permit function.
let _ = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.permit".to_string()),
message: OwnedParameter::from_serial(&permit_update_operator_param)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to update operator with permit");

// Check operator in state
let operator_of_query = OperatorOfQuery {
address: ADDR_OWNER,
owner: ADDR_OTHER,
};

let operator_of_query_vector = OperatorOfQueryParams {
queries: vec![operator_of_query],
};

// Check operator in state
let update = chain
.contract_update(
Signer::with_one_key(),
ACC_ADDR_OWNER,
Address::Account(ACC_ADDR_OWNER),
Energy::from(10000),
UpdateContractPayload {
amount: Amount::zero(),
address: initialization.contract_address,
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.operatorOf".to_string()),
message: OwnedParameter::from_serial(&operator_of_query_vector)
.expect("Should be a valid inut parameter"),
},
)
.expect("Should be able to query operatorOf");

let is_operator_of: OperatorOfQueryResponse =
from_bytes(&update.return_value).expect("View should always return a valid result");

assert!(update.is_ok());
assert_eq!(is_operator_of.0, [true])
}

0 comments on commit 965754a

Please sign in to comment.