Skip to content

Commit d9fe46d

Browse files
authored
A0-1140: e2e tests for contracts (#697)
* Fix invalid clap default * Setup framework for testing the button * Test early bird play * Test marketplace contract * Test all button game variants * Run contract e2e tests on CI * Bump aleph_client version * Fix cache target list * Fix clippy warnings * Simplify scopes * Add docs * Use From/TryFrom instead of custom traits * Allow minting only in dev * Fix clippy
1 parent fb8c407 commit d9fe46d

File tree

24 files changed

+946
-165
lines changed

24 files changed

+946
-165
lines changed

.github/workflows/contracts-e2e-tests-and-deploy.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,15 @@ jobs:
6060
target-key: e2e-contracts
6161
cargo-key: e2e-contracts
6262
cache-version: v3
63-
cargo-targets: e2e-tests-contracts/target/
63+
cargo-targets: |
64+
e2e-tests/target/
65+
contracts/access_control/target/
66+
contracts/button/target/
67+
contracts/game_token/target/
68+
contracts/marketplace/target/
69+
contracts/simple_dex/target/
70+
contracts/ticket_token/target/
71+
contracts/wrapped_azero/target/
6472
6573
- name: Install cargo-contract
6674
run: |

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aleph-client/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aleph-client/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aleph_client"
3-
version = "1.9.0"
3+
version = "1.10.0"
44
edition = "2021"
55
license = "Apache 2.0"
66

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use std::ops::Deref;
2+
3+
use anyhow::{bail, Result};
4+
use contract_transcode::Value;
5+
use sp_core::crypto::Ss58Codec;
6+
7+
use crate::AccountId;
8+
9+
/// Temporary wrapper for converting from [Value] to primitive types.
10+
///
11+
/// ```
12+
/// # #![feature(assert_matches)]
13+
/// # #![feature(type_ascription)]
14+
/// # use std::assert_matches::assert_matches;
15+
/// # use anyhow::{anyhow, Result};
16+
/// # use aleph_client::{AccountId, contract::ConvertibleValue};
17+
/// use contract_transcode::Value;
18+
///
19+
/// assert_matches!(ConvertibleValue(Value::UInt(42)).try_into(), Ok(42));
20+
/// assert_matches!(ConvertibleValue(Value::Bool(true)).try_into(), Ok(true));
21+
/// assert_matches!(
22+
/// ConvertibleValue(Value::Literal("5H8cjBBzCJrAvDn9LHZpzzJi2UKvEGC9VeVYzWX5TrwRyVCA".to_string())).
23+
/// try_into(): Result<AccountId>,
24+
/// Ok(_)
25+
/// );
26+
/// assert_matches!(
27+
/// ConvertibleValue(Value::String("not a number".to_string())).try_into(): Result<u128>,
28+
/// Err(_)
29+
/// );
30+
/// ```
31+
#[derive(Debug, Clone)]
32+
pub struct ConvertibleValue(pub Value);
33+
34+
impl Deref for ConvertibleValue {
35+
type Target = Value;
36+
37+
fn deref(&self) -> &Value {
38+
&self.0
39+
}
40+
}
41+
42+
impl TryFrom<ConvertibleValue> for bool {
43+
type Error = anyhow::Error;
44+
45+
fn try_from(value: ConvertibleValue) -> Result<bool, Self::Error> {
46+
match value.0 {
47+
Value::Bool(value) => Ok(value),
48+
_ => bail!("Expected {:?} to be a boolean", value.0),
49+
}
50+
}
51+
}
52+
53+
impl TryFrom<ConvertibleValue> for u128 {
54+
type Error = anyhow::Error;
55+
56+
fn try_from(value: ConvertibleValue) -> Result<u128, Self::Error> {
57+
match value.0 {
58+
Value::UInt(value) => Ok(value),
59+
_ => bail!("Expected {:?} to be an integer", value.0),
60+
}
61+
}
62+
}
63+
64+
impl TryFrom<ConvertibleValue> for AccountId {
65+
type Error = anyhow::Error;
66+
67+
fn try_from(value: ConvertibleValue) -> Result<AccountId, Self::Error> {
68+
match value.0 {
69+
Value::Literal(value) => Ok(AccountId::from_ss58check(&value)?),
70+
_ => bail!("Expected {:?} to be a string", value),
71+
}
72+
}
73+
}

aleph-client/src/contract/mod.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@
55
//!
66
//! ```no_run
77
//! # use anyhow::{Result, Context};
8-
//! # use sp_core::crypto::AccountId32;
8+
//! # use aleph_client::AccountId;
99
//! # use aleph_client::{Connection, SignedConnection};
1010
//! # use aleph_client::contract::ContractInstance;
11-
//! # use aleph_client::contract::util::to_u128;
1211
//! #
1312
//! #[derive(Debug)]
1413
//! struct PSP22TokenInstance {
1514
//! contract: ContractInstance,
1615
//! }
1716
//!
1817
//! impl PSP22TokenInstance {
19-
//! fn new(address: AccountId32, metadata_path: &Option<String>) -> Result<Self> {
18+
//! fn new(address: AccountId, metadata_path: &Option<String>) -> Result<Self> {
2019
//! let metadata_path = metadata_path
2120
//! .as_ref()
2221
//! .context("PSP22Token metadata not set.")?;
@@ -25,26 +24,26 @@
2524
//! })
2625
//! }
2726
//!
28-
//! fn transfer(&self, conn: &SignedConnection, to: AccountId32, amount: u128) -> Result<()> {
27+
//! fn transfer(&self, conn: &SignedConnection, to: AccountId, amount: u128) -> Result<()> {
2928
//! self.contract.contract_exec(
3029
//! conn,
3130
//! "PSP22::transfer",
3231
//! vec![to.to_string().as_str(), amount.to_string().as_str(), "0x00"].as_slice(),
3332
//! )
3433
//! }
3534
//!
36-
//! fn balance_of(&self, conn: &Connection, account: AccountId32) -> Result<u128> {
37-
//! to_u128(self.contract.contract_read(
35+
//! fn balance_of(&self, conn: &Connection, account: AccountId) -> Result<u128> {
36+
//! self.contract.contract_read(
3837
//! conn,
3938
//! "PSP22::balance_of",
4039
//! &vec![account.to_string().as_str()],
41-
//! )?)
40+
//! )?.try_into()
4241
//! }
4342
//! }
4443
//! ```
4544
45+
mod convertible_value;
4646
pub mod event;
47-
pub mod util;
4847

4948
use std::{
5049
fmt::{Debug, Formatter},
@@ -54,36 +53,37 @@ use std::{
5453
use ac_primitives::ExtrinsicParams;
5554
use anyhow::{anyhow, Context, Result};
5655
use contract_metadata::ContractMetadata;
57-
use contract_transcode::{ContractMessageTranscoder, Value};
56+
use contract_transcode::ContractMessageTranscoder;
57+
pub use convertible_value::ConvertibleValue;
5858
use ink_metadata::{InkProject, MetadataVersioned};
5959
use serde_json::{from_reader, from_str, from_value, json};
60-
use sp_core::{crypto::AccountId32, Pair};
60+
use sp_core::Pair;
6161
use substrate_api_client::{compose_extrinsic, GenericAddress, XtStatus};
6262

63-
use crate::{try_send_xt, AnyConnection, SignedConnection};
63+
use crate::{try_send_xt, AccountId, AnyConnection, SignedConnection};
6464

6565
/// Represents a contract instantiated on the chain.
6666
pub struct ContractInstance {
67-
address: AccountId32,
67+
address: AccountId,
6868
ink_project: InkProject,
6969
}
7070

7171
impl ContractInstance {
7272
const MAX_READ_GAS: u64 = 500000000000u64;
73-
const MAX_GAS: u64 = 10000000000u64;
73+
const MAX_GAS: u64 = 100000000000u64;
7474
const PAYABLE_VALUE: u64 = 0u64;
7575
const STORAGE_FEE_LIMIT: Option<u128> = None;
7676

7777
/// Creates a new contract instance under `address` with metadata read from `metadata_path`.
78-
pub fn new(address: AccountId32, metadata_path: &str) -> Result<Self> {
78+
pub fn new(address: AccountId, metadata_path: &str) -> Result<Self> {
7979
Ok(Self {
8080
address,
8181
ink_project: load_metadata(metadata_path)?,
8282
})
8383
}
8484

8585
/// The address of this contract instance.
86-
pub fn address(&self) -> &AccountId32 {
86+
pub fn address(&self) -> &AccountId {
8787
&self.address
8888
}
8989

@@ -93,7 +93,11 @@ impl ContractInstance {
9393
}
9494

9595
/// Reads the value of a read-only, 0-argument call via RPC.
96-
pub fn contract_read0<C: AnyConnection>(&self, conn: &C, message: &str) -> Result<Value> {
96+
pub fn contract_read0<C: AnyConnection>(
97+
&self,
98+
conn: &C,
99+
message: &str,
100+
) -> Result<ConvertibleValue> {
97101
self.contract_read(conn, message, &[])
98102
}
99103

@@ -103,7 +107,7 @@ impl ContractInstance {
103107
conn: &C,
104108
message: &str,
105109
args: &[&str],
106-
) -> Result<Value> {
110+
) -> Result<ConvertibleValue> {
107111
let payload = self.encode(message, args)?;
108112
let request = self.contract_read_request(&payload);
109113
let response = conn
@@ -166,10 +170,12 @@ impl ContractInstance {
166170
ContractMessageTranscoder::new(&self.ink_project).encode(message, args)
167171
}
168172

169-
fn decode_response(&self, from: &str, contract_response: &str) -> Result<Value> {
173+
fn decode_response(&self, from: &str, contract_response: &str) -> Result<ConvertibleValue> {
170174
let contract_response = contract_response.trim_start_matches("0x");
171175
let bytes = hex::decode(contract_response)?;
172-
ContractMessageTranscoder::new(&self.ink_project).decode_return(from, &mut bytes.as_slice())
176+
ContractMessageTranscoder::new(&self.ink_project)
177+
.decode_return(from, &mut bytes.as_slice())
178+
.map(ConvertibleValue)
173179
}
174180
}
175181

aleph-client/src/contract/util.rs

Lines changed: 0 additions & 48 deletions
This file was deleted.

aleph-client/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use ac_primitives::{PlainTipExtrinsicParamsBuilder, SubstrateDefaultSignedExtra}
44
pub use account::{get_free_balance, locks};
55
pub use balances::total_issuance;
66
use codec::{Decode, Encode};
7+
pub use contract_transcode;
78
pub use debug::print_storages;
89
pub use elections::{
910
get_committee_seats, get_current_era_non_reserved_validators,

bin/cliain/src/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub struct ContractOptions {
1616
#[clap(long, default_value = "0")]
1717
pub balance: u128,
1818
/// The gas limit enforced when executing the constructor
19-
#[clap(long, default_value = "1_000_000_000")]
19+
#[clap(long, default_value = "1000000000")]
2020
pub gas_limit: u64,
2121
/// The maximum amount of balance that can be charged/reserved from the caller to pay for the storage consumed
2222
#[clap(long)]

contracts/button/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod errors;
55
use ink_lang as ink;
66

77
#[ink::contract]
8-
mod button_game {
8+
pub mod button_game {
99
use access_control::{roles::Role, traits::AccessControlled, ACCESS_CONTROL_PUBKEY};
1010
use game_token::MINT_SELECTOR;
1111
use ink_env::{

0 commit comments

Comments
 (0)