Skip to content

Commit

Permalink
Merge pull request #413 from Concordium/account-abstracted-smart-cont…
Browse files Browse the repository at this point in the history
…ract-wallet

Add smart contract wallet
  • Loading branch information
DOBEN authored Apr 16, 2024
2 parents 03f677d + 4a67ac9 commit a932404
Show file tree
Hide file tree
Showing 8 changed files with 2,358 additions and 19 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
- examples/cis2-wccd/Cargo.toml
- examples/cis3-nft-sponsored-txs/Cargo.toml
- examples/counter-notify/Cargo.toml
- examples/cis5-smart-contract-wallet/Cargo.toml
- examples/credential-registry/Cargo.toml
- examples/eSealing/Cargo.toml
- examples/factory/Cargo.toml
Expand Down Expand Up @@ -714,6 +715,7 @@ jobs:
- examples/cis2-nft/Cargo.toml
- examples/cis3-nft-sponsored-txs/Cargo.toml
- examples/cis2-wccd/Cargo.toml
- examples/cis5-smart-contract-wallet/Cargo.toml
- examples/credential-registry/Cargo.toml
- examples/factory/Cargo.toml
- examples/fib/Cargo.toml
Expand Down Expand Up @@ -847,6 +849,7 @@ jobs:
- examples/cis2-nft
- examples/cis3-nft-sponsored-txs
- examples/cis2-wccd
- examples/cis5-smart-contract-wallet
- examples/credential-registry
- examples/factory
- examples/fib
Expand Down Expand Up @@ -894,9 +897,9 @@ jobs:
if: ${{ matrix.crates == 'examples/smart-contract-upgrade/contract-version1' }}
run: cargo concordium build --out "examples/smart-contract-upgrade/contract-version2/concordium-out/module.wasm.v1" -- --manifest-path "examples/smart-contract-upgrade/contract-version2/Cargo.toml"

# The 'sponsored-tx-enabled-auction' example needs the wasm module `cis2-multi` for its tests.
# The 'sponsored-tx-enabled-auction' and 'cis5-smart-contract-wallet' examples need the wasm module `cis2-multi` for its tests.
- name: Build cis2-multi module if needed
if: ${{ matrix.crates == 'examples/sponsored-tx-enabled-auction' }}
if: ${{ matrix.crates == 'examples/sponsored-tx-enabled-auction' || matrix.crates == 'examples/cis5-smart-contract-wallet'}}
run: cargo concordium build --out "examples/cis2-multi/concordium-out/module.wasm.v1" -- --manifest-path "examples/cis2-multi/Cargo.toml"

- name: Run cargo concordium test
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The list of contracts is as follows:
- [proxy](./proxy) A proxy contract that can be put in front of another contract. It works with V0 as well as V1 smart contracts.
- [recorder](./recorder) A contract that records account addresses, and has an entry point to invoke transfers to all those addresses.
- [signature-verifier](./signature-verifier) An example of how to use `crypto_primitives`. The contract verifies an Ed25519 signature.
- [cis5-smart-contract-wallet](./cis5-smart-contract-wallet) An example of how to implement a CIS5 compatible smart contract wallet.
- [nametoken](./nametoken) An example of how to register and manage names as tokens in a smart contract.
- [voting](./voting) An example of how to conduct an election using a smart contract.
- [transfer-policy-check](./transfer-policy-check) A contract that showcases how to use policies.
Expand Down
31 changes: 23 additions & 8 deletions examples/cis2-multi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,14 +320,16 @@ pub type ContractTokenAmount = TokenAmountU64;

/// The parameter for the contract function `mint` which mints/airdrops a number
/// of tokens to the owner's address.
#[derive(Serialize, SchemaType)]
#[derive(Serialize, SchemaType, Clone)]
pub struct MintParams {
/// Owner of the newly minted tokens.
pub owner: Address,
pub to: Receiver,
/// The metadata_url of the token.
pub metadata_url: MetadataUrl,
/// The token_id to mint/create additional tokens.
pub token_id: ContractTokenId,
/// Additional data that can be sent to the receiving contract.
pub data: AdditionalData,
}

/// The parameter for the contract function `burn` which burns a number
Expand Down Expand Up @@ -952,11 +954,13 @@ fn contract_view(_ctx: &ReceiveContext, host: &Host<State>) -> ReceiveResult<Vie
/// function of the state. Logs a `Mint` event.
/// The function assumes that the mint is authorized.
fn mint(
params: MintParams,
params: &MintParams,
host: &mut Host<State>,
logger: &mut impl HasLogger,
) -> ContractResult<()> {
let is_blacklisted = host.state().blacklist.contains(&get_canonical_address(params.owner)?);
let to_address = params.to.address();

let is_blacklisted = host.state().blacklist.contains(&get_canonical_address(to_address)?);

// Check token owner is not blacklisted.
ensure!(!is_blacklisted, CustomContractError::Blacklisted.into());
Expand All @@ -970,7 +974,7 @@ fn mint(
let token_metadata = state.mint(
&params.token_id,
&params.metadata_url,
&params.owner,
&to_address,
state.mint_airdrop,
builder,
);
Expand All @@ -979,7 +983,7 @@ fn mint(
logger.log(&Cis2Event::Mint(MintEvent {
token_id: params.token_id,
amount: state.mint_airdrop,
owner: params.owner,
owner: to_address,
}))?;

// Metadata URL for the token.
Expand Down Expand Up @@ -1030,7 +1034,18 @@ fn contract_mint(
// ensure!(host.state().has_role(&sender, Roles::MINTER),
// ContractError::Unauthorized);

mint(params, host, logger)?;
mint(&params, host, logger)?;

// If the receiver is a contract: invoke the receive hook function.
if let Receiver::Contract(address, function) = params.to {
let parameter = OnReceivingCis2Params {
token_id: params.token_id,
amount: host.state.mint_airdrop,
from: Address::from(address),
data: params.data,
};
host.invoke_contract(&address, &parameter, function.as_entrypoint_name(), Amount::zero())?;
}

Ok(())
}
Expand Down Expand Up @@ -1383,7 +1398,7 @@ fn contract_permit(
// ContractError::Unauthorized
// );

mint(params, host, logger)?;
mint(&params, host, logger)?;
}
BURN_ENTRYPOINT => {
// Burn tokens.
Expand Down
15 changes: 10 additions & 5 deletions examples/cis2-multi/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,12 +313,13 @@ fn test_permit_mint() {

// Create input parameters for the `mint` function.
let payload = MintParams {
owner: ALICE_ADDR,
to: Receiver::from_account(ALICE),
metadata_url: MetadataUrl {
url: "https://some.example/token/2A".to_string(),
hash: None,
},
token_id: TOKEN_1,
data: AdditionalData::empty(),
};

let update =
Expand Down Expand Up @@ -893,12 +894,13 @@ fn test_token_balance_of_blacklisted_address_can_not_change() {

// Bob cannot mint tokens to its address.
let mint_params = MintParams {
owner: BOB_ADDR,
to: Receiver::from_account(BOB),
token_id: TOKEN_0,
metadata_url: MetadataUrl {
url: "https://some.example/token/02".to_string(),
hash: None,
},
data: AdditionalData::empty(),
};

let update = chain
Expand Down Expand Up @@ -1101,12 +1103,13 @@ fn test_no_execution_of_state_mutative_functions_when_paused() {

// Try to mint tokens.
let params = MintParams {
owner: ALICE_ADDR,
to: Receiver::from_account(ALICE),
metadata_url: MetadataUrl {
url: "https://some.example/token/02".to_string(),
hash: None,
},
token_id: TOKEN_0,
data: AdditionalData::empty(),
};

let update_operator = chain
Expand Down Expand Up @@ -1306,12 +1309,13 @@ fn initialize_contract_with_alice_tokens(
let (mut chain, keypairs, contract_address, module_reference) = initialize_chain_and_contract();

let mint_params = MintParams {
owner: ALICE_ADDR,
to: Receiver::from_account(ALICE),
token_id: TOKEN_0,
metadata_url: MetadataUrl {
url: "https://some.example/token/02".to_string(),
hash: None,
},
data: AdditionalData::empty(),
};

// Mint/airdrop TOKEN_0 to Alice as the owner.
Expand All @@ -1325,12 +1329,13 @@ fn initialize_contract_with_alice_tokens(
.expect("Mint tokens");

let mint_params = MintParams {
owner: ALICE_ADDR,
to: Receiver::from_account(ALICE),
token_id: TOKEN_1,
metadata_url: MetadataUrl {
url: "https://some.example/token/2A".to_string(),
hash: None,
},
data: AdditionalData::empty(),
};

// Mint/airdrop TOKEN_1 to Alice as the owner.
Expand Down
29 changes: 29 additions & 0 deletions examples/cis5-smart-contract-wallet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "smart-contract-wallet"
version = "0.1.0"
authors = ["Concordium <developers@concordium.com>"]
edition = "2021"
license = "MPL-2.0"

[features]
default = ["std", "bump_alloc"]
std = ["concordium-std/std", "concordium-cis2/std"]
bump_alloc = ["concordium-std/bump_alloc"]

[dependencies]
concordium-std = {path = "../../concordium-std", default-features = false}
concordium-cis2 = {path = "../../concordium-cis2", default-features = false, features=[
"u256_amount"]}

[dev-dependencies]
concordium-smart-contract-testing = {path = "../../contract-testing"}
cis2-multi = {path = "../cis2-multi"}
ed25519-dalek = { version = "2.0", features = ["rand_core"] }
rand = "0.8"

[lib]
crate-type=["cdylib", "rlib"]

[profile.release]
codegen-units = 1
opt-level = "s"
Loading

0 comments on commit a932404

Please sign in to comment.