diff --git a/Cargo.lock b/Cargo.lock index bfc9981..4b5fb1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3473,7 +3473,6 @@ dependencies = [ "frame-system", "log", "pallet-assets", - "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -3918,7 +3917,7 @@ dependencies = [ "frame-system", "log", "pallet-assets", - "pallet-nfts 30.0.0", + "pallet-nfts", "parity-scale-codec", "scale-info", "sp-runtime", @@ -3944,29 +3943,13 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-nfts" -version = "31.0.0" -dependencies = [ - "enumflags2", - "frame-benchmarking", - "frame-support", - "frame-system", - "log", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", -] - [[package]] name = "pallet-nfts-runtime-api" version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0ca7a0446d2d3c27f726a016c6366218df2e0bfef9ed35886b252cfa9757f6c" dependencies = [ - "pallet-nfts 30.0.0", + "pallet-nfts", "parity-scale-codec", "sp-api", "sp-std", @@ -4754,7 +4737,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", + "pallet-nfts", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/README.md b/README.md index 2e17b48..4116a1a 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,85 @@ -

Pop DRink! (forked from DRink!)

-

Dechained Ready-to-play ink! playground

+
+

Pop DRink!

-> [!IMPORTANT] -> This repository is customized and maintained for Pop API contract end-to-end testing. -> -> Quasi tests must be run with `cargo test --release`. +R0GUE Logo -# Pop Sandbox +[![Twitter URL](https://img.shields.io/twitter/follow/Pop?style=social)](https://x.com/onpopio/) +[![Twitter URL](https://img.shields.io/twitter/follow/R0GUE?style=social)](https://twitter.com/gor0gue) +[![Telegram](https://img.shields.io/badge/Telegram-gray?logo=telegram)](https://t.me/onpopio) -Implementation of the [`pop_drink::Sandbox`](https://github.com/r0gue-io/pop-drink) struct for the Pop Network runtimes (located in `pop-node/runtime`) required for the quasi testing with `drink`. +Forked version of [inkdevhub/drink](https://github.com/inkdevhub/drink) for E2E testing of smart contract using the [Pop API](https://github.com/r0gue-io/pop-node/tree/main/pop-api) on Pop Network. -In the context of quasi-testing with pop-drink, a sandbox refers to an isolated runtime environment that simulates the behavior of a full node, without requiring an actual node. It can emulate key processes (where runtime `pallets` are involved) such as block initialization, execution, and block finalization. +
+ +## Overview + +About the repository folder structure: + +- [pop-drink](/crates/pop-drink): Library for testing contracts deployed on Pop Network using drink. +- [drink](/crates/drink/drink): drink is a toolbox for ink! developers to test contracts in a sandbox environment. +- [ink-sandbox](/crates/ink-sandbox): Creates a sandbox environment for a given runtime, without having to run a node. +- [examples](/crates/drink/examples): A collection of example contracts tested with drink. +- [drink-cli](/crates/drink/drink-cli): Simple command line tool to help you play with your local contracts in a convenient way. ## Getting Started -### Installation +Add `pop-drink` crate to your contract `Cargo.toml`: ```toml -pop_drink = { version = "1.0.0", package = "pop-drink" } +drink = { version = "1.0.0", package = "pop-drink" } ``` -### Import Sandbox for the specific runtime - -- For `devnet` runtime - -Implementation of the sandbox runtime environment for `devnet` runtime located in `pop-node/runtime/devnet` +Set up your pop-drink test environment and write your first test. ```rs -use pop_sandbox::DevnetSandbox; -``` +use drink::{ + devnet::{AccountId, Balance, Runtime}, + TestExternalities, + deploy, call, +}; -- For `testnet` runtime -Implementation of the sandbox runtime environment for `testnet` runtime located in `pop-node/runtime/testnet` +// Builds your contract(s). +#[drink::contract_bundle_provider] +enum BundleProvider {} -```rs -use pop_sandbox::TestnetSandbox; -``` +/// Sandbox environment for Pop Devnet Runtime. +pub struct Pop { + ext: TestExternalities, +} -- For `mainnet` runtime +// Initialising genesis state. +impl Default for Pop { + fn default() -> Self { + let balances: Vec<(AccountId, Balance)> = vec![(ALICE, 100u128)]; + let ext = BlockBuilder::::new_ext(balances); + Self { ext } + } +} -Implementation of the sandbox runtime environment for `mainnet` runtime located in `pop-node/runtime/mainnet` +// Implement core functionalities for the `Pop` sandbox. +drink::impl_sandbox!(Pop, Runtime, ALICE); -```rs -use pop_sandbox::MainnetSandbox; +// Write your first pop-drink test! +#[drink::test(sandbox = Pop)] +fn test(mut session: Session) { ... } ``` -### Setup test environment for your contract +Important: run your tests with `--release` +``` +cargo test --release +``` -Below is an example for the contract testing with `pop_drink` and `pop_sandbox` for `devnet` environment using `DevnetSandbox`. +## Learn more -```rs -use pop_drink::session::Session; -use pop_sandbox::DevnetSandbox as Sandbox; +Dive into the ["quick start with drink!"](/crates/drink/examples/quick-start-with-drink/README.md) to learn more about drink. Also check out the other examples provided by drink. -#[drink::contract_bundle_provider] -enum BundleProvider {} +If you are interested in learning more about testing contracts using the Pop API, check out the [example contracts](https://github.com/r0gue-io/pop-node/tree/main/pop-api/examples) tested with pop-drink! -#[drink::test(sandbox = Sandbox)] -fn test(mut session: Session) { - // Your test case -} -``` +## Support + +Be part of our passionate community of Web3 builders. [Join our Telegram](https://t.me/onpopio)! -## Examples +Feel free to contribute to `drink` or `pop-drink` to help improve testing ink! smart contracts! -Please find more examples of `pop_drink` tests in the [`pop_drink/examples`](https://github.com/r0gue-io/pop-drink/tree/main/examples). +For any questions related to ink! you can also go to [Polkadot Stack Exchange](https://polkadot.stackexchange.com/) or ask the [ink! community](https://t.me/inkathon/1). \ No newline at end of file diff --git a/crates/pop-drink/Cargo.toml b/crates/pop-drink/Cargo.toml index cd95815..e82fa10 100644 --- a/crates/pop-drink/Cargo.toml +++ b/crates/pop-drink/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -scale-info = { workspace = true, default-features = false, features = [ - "derive", -] } - drink.workspace = true ink_sandbox.workspace = true pallet-contracts.workspace = true @@ -19,6 +15,7 @@ scale.workspace = true pop-api.workspace = true [dev-dependencies] +scale-info = { workspace = true, features = ["derive"] } pallet-api.workspace = true pallet-assets.workspace = true pallet-balances.workspace = true diff --git a/crates/pop-drink/src/error.rs b/crates/pop-drink/src/error.rs index dd43094..8d2c528 100644 --- a/crates/pop-drink/src/error.rs +++ b/crates/pop-drink/src/error.rs @@ -1,4 +1,4 @@ -//! A set of errors used for testing smart contracts. +//! The error type and utilities for testing smart contracts using the Pop API. use std::fmt::Debug; @@ -8,33 +8,166 @@ pub use drink::{ }; use scale::{Decode, Encode}; -fn decode(data: &[u8]) -> T { - T::decode(&mut &data[..]).expect("Decoding failed") +/// A simplified error type representing errors from the runtime and its modules. +/// +/// This type can be used to assert to an error that holds a [status code](https://github.com/r0gue-io/pop-node/blob/main/pop-api/src/lib.rs#L33). +/// The status code is returned by the Pop API and represents a runtime error. +/// +/// # Generic Parameters: +/// - `ApiError`: The pop api error type. +/// - `ModuleError`: The error type for specific runtime modules. +/// - `MODULE_INDEX`: Index of the variant `Error::Module`. +#[derive(Encode, Decode, Debug)] +pub enum Error +where + ApiError: Decode + Encode + Debug + From + Into, + ModuleError: Decode + Encode + Debug, +{ + /// An error not related to any specific module. + Raw(ApiError), + /// An error originating from a runtime module. + Module(ModuleError), +} + +impl From> + for u32 +where + ApiError: Decode + Encode + Debug + From + Into, + ModuleError: Decode + Encode + Debug, +{ + /// Converts an `Error` to a `u32` status code. + fn from(error: Error) -> Self { + match error { + Error::Raw(error) => decode::(&error.encode()), + Error::Module(error) => { + let mut encoded = error.encode(); + encoded.insert(0, MODULE_INDEX); + encoded.resize(4, 0); + decode::(&encoded) + }, + } + .into() + } +} + +impl From + for Error +where + ApiError: Decode + Encode + Debug + From + Into, + ModuleError: Decode + Encode + Debug, +{ + /// Converts a `u32` into an `Error`. + /// + /// If the status code represents a module error it converts it into `Error::Module` in stead + /// of `Error::Raw`. + fn from(value: u32) -> Self { + let error = ApiError::from(value); + let encoded = error.encode(); + if encoded[0] == MODULE_INDEX { + let (index, module_error) = (encoded[1], &encoded[2..]); + let data = vec![vec![index], module_error.to_vec()].concat(); + return Error::Module(decode(&data)); + } + Error::Raw(error) + } } -/// Asserts a custom error type against the `Error`. This is useful when you want to check if a contract's custom error (e.g., [`PSP22Error`](https://github.com/r0gue-io/pop-node/blob/main/pop-api/src/v0/fungibles/errors.rs#L73C1-L73C22)) matches the error code returned by the runtime, which is represented by a [`StatusCode`](https://github.com/r0gue-io/pop-node/blob/main/pop-api/src/lib.rs#L33). The error type must be convertible to a `u32`. +/// Asserts that a result matches an expected `Error`. +/// +/// This can be used to assert that a contract execution resulted in a specific runtime error +/// `Error`. The contract error must be convertible to a `u32` (i.e. the status code received from +/// the api). +/// +/// # Example +/// +/// ## Errors +/// +/// ```rs +/// use drink::devnet::{ +/// Assets, +/// AssetsError::BalanceLow, +/// v0::{ +/// Arithmetic, +/// ArithmeticError::Overflow, +/// BadOrigin +/// }, +/// }; +/// ``` /// -/// # Parameters +/// [`BadOrigin`](https://github.com/r0gue-io/pop-node/blob/main/primitives/src/lib.rs#L36C4-L36C18): +/// ```rs +/// Error::Raw(BadOrigin) +/// ``` +/// +/// [`Arithmetic(Overflow)`](https://github.com/r0gue-io/pop-node/blob/main/primitives/src/lib.rs#L55): +/// ```rs +/// Error::Raw(Arithmetic(Overflow)) +/// ``` /// -/// - `result` - Contract method's result returns the custom error type which is convertible to -/// `u32`. -/// - `error` - `Error` to assert against the custom error type. +/// [`Assets(BalanceLow)`](https://paritytech.github.io/polkadot-sdk/master/pallet_assets/pallet/enum.Error.html#variant.BalanceLow): +/// ```rs +/// Error::Module(Assets(BalanceLow)) +/// ``` /// -/// # Examples +/// ## How to use `assert_err` macro. /// -/// To assert the `StatusCode` returned by a contract method that uses Pop API, you simply use the -/// provided `assert_err!` macro. +/// - Create a custom error type that holds the status code. /// /// ```rs -/// // Required imports to test the custom error. -/// use drink::{ assert_err, devnet::error::{ v0::Error, Arithmetic, ArithmeticError::Overflow }}; +/// use pop_api::StatusCode; +/// +/// /// Custom error in contract. +/// pub enum CustomError { +/// ..., +/// /// Error with status code. +/// StatusCode(u32), +/// } +/// +/// impl From for CustomError { +/// /// Converts a `StatusCode` (returned by the api) to a `CustomError`. +/// fn from(value: StatusCode) -> Self { +/// match value { +/// ..., +/// _ => CustomError::StatusCode(value.0), +/// } +/// } +/// } +/// +/// impl From for u32 { +/// /// Converts a `CustomError to a `u32`. +/// // +/// // Required for the `assert_err` macro to assert to `Error`. +/// fn from(value: CustomError) -> Self { +/// match value { +/// ..., +/// CustomError::StatusCode(status_code) => status_code, +/// } +/// } +/// } /// -/// // Call a contract method named "hello_world" that throws `StatusCode`. -/// let result = call::(session, "hello_world", vec![], None); +/// - Use `assert_err` in a test. /// -/// // Asserts that the call fails because of an arithmetic operation error. -/// assert_err!(result, Error::Raw(Arithmetic(Overflow))); +/// #[drink::test(sandbox = Pop)] +/// fn test_custom_error(mut session: Session) { +/// ... +/// +/// // Call a contract method that returns a `Result<(), CustomError>`. +/// let result = call::(session, "hello_world", vec![], None); +/// +/// // Assert the result to the expected error. +/// assert_err!(result, Error::Raw(BadOrigin))); +/// +/// // Other assertions: +/// ... +/// assert_err!(result, Error::Raw(Arithmetic(Overflow))); +/// ... +/// assert_err!(result, Error::Module(Assets(BalanceLow))); +/// } /// ``` +/// +/// # Parameters: +/// - `result`: The result which contains the custom error type. +/// - `error`: The expected error. #[macro_export] macro_rules! assert_err { ($result:expr, $error:expr $(,)?) => { @@ -42,22 +175,9 @@ macro_rules! assert_err { }; } -/// Asserts an error type to Error. This can be used for custom error types used by a contract which -/// uses the [`StatusCode`](https://github.com/r0gue-io/pop-node/blob/main/pop-api/src/lib.rs#L33) returned by the pop runtime. The error type must be convertible to a `u32`. -/// -/// # Generic parameters -/// -/// - `R` - Type returned if `result` is `Ok()`. -/// - `E` - Type returned if `result` is `Err()`. Must be convertible to `u32`. -/// - `Error` - `Error` to assert against the custom error type. -/// -/// # Parameters -/// -/// - `result` - Contract method's result returns the custom error type which is convertible to -/// `u32`. -/// - `expected_error` - `Error` to assert against the custom error type. #[track_caller] -pub fn assert_err_inner(result: Result, expected_error: Error) +#[allow(unused)] +fn assert_err_inner(result: Result, expected_error: Error) where E: Into, Error: From + Into + Debug, @@ -85,177 +205,40 @@ where } } -/// Error type for testing why a runtime call fails. -/// -/// # Generic Parameters -/// -/// - [`RuntimeCallError`](https://github.com/r0gue-io/pop-node/blob/main/primitives/src/lib.rs#L30) -/// - Reason why a runtime call fails. (.e.g, arithmetic operation errors) -/// - [`ModuleError`](https://paritytech.github.io/polkadot-sdk/master/solochain_template_runtime/enum.Error.html) -/// - Refers to specific reasons a runtime call fails, originating from the runtime modules. -/// - [`MODULE_INDEX`](https://github.com/r0gue-io/pop-node/blob/main/primitives/src/lib.rs#L38) -/// - Index of the variant `Error::Module`. -/// -/// # Examples -/// -/// ### Runtime call errors -/// -/// - Import types to construct runtime call errors: -/// -/// ```rs -/// use drink::devnet::v0::{ -/// Arithmetic, -/// ArithmeticError::Overflow, -/// BadOrigin -/// }; -/// ``` -/// -/// - Runtime call error [`Arithmetic(Overflow)`](https://github.com/r0gue-io/pop-node/blob/main/primitives/src/lib.rs#L55): -/// -/// ```rs -/// Error::Raw(Arithmetic(Overflow)) -/// ``` -/// -/// - Runtime call error [`BadOrigin`](https://github.com/r0gue-io/pop-node/blob/main/primitives/src/lib.rs#L36C4-L36C18): -/// -/// ```rs -/// Error::Raw(BadOrigin) -/// ``` -/// -/// ### Runtime module errors -/// -/// - Import types to construct runtime module errors: -/// -/// ```rs -/// use drink::devnet::{ -/// Assets, -/// AssetsError::AssetNotLive, -/// Balances::BelowMinimum, -/// BalancesError::BelowMinimum -/// }; -/// ``` -/// -/// - Construct a runtime module error [`Assets(AssetNotLive)`](https://paritytech.github.io/polkadot-sdk/master/pallet_assets/pallet/enum.Error.html#variant.AssetNotLive): -/// -/// ```rs -/// Error::Module(Assets(AssetNotLive)) -/// ``` -/// -/// - Construct a runtime module error [`Balances(InsufficientBalance)`](https://docs.rs/pallet-balances/latest/pallet_balances/pallet/enum.Error.html#variant.InsufficientBalance): -/// -/// ```rs -/// Error::Module(Balances(InsufficientBalance)) -/// ``` - -#[derive(Encode, Decode, Debug)] -pub enum Error -where - RuntimeCallError: Decode + Encode + Debug + From + Into, - ModuleError: Decode + Encode + Debug, -{ - /// Reason why a runtime call fails. [Reference](https://github.com/r0gue-io/pop-node/blob/52fb7f06a89955d462900e33d2b9c9170c4534a0/primitives/src/lib.rs#L30). - Raw(RuntimeCallError), - /// [Module error](https://paritytech.github.io/polkadot-sdk/master/solochain_template_runtime/enum.Error.html) refers to specific reasons a runtime call fails, originating from the runtime modules. - Module(ModuleError), -} - -impl - From> for u32 -where - RuntimeCallError: Decode + Encode + Debug + From + Into, - ModuleError: Decode + Encode + Debug, -{ - /// Converts an `Error` to a `u32` number. - /// - /// This conversion is necessary for comparing `Error` instances with other types. - // Compared types must implement `Into`, as `Error` does not implement `Eq`. - // Use this function to obtain a numerical representation of the error for comparison or - // further processing. - fn from(error: Error) -> Self { - match error { - Error::Raw(error) => decode::(&error.encode()), - Error::Module(error) => { - let mut encoded = error.encode(); - encoded.insert(0, MODULE_INDEX); - encoded.resize(4, 0); - decode::(&encoded) - }, - } - .into() - } -} - -impl From - for Error -where - RuntimeCallError: Decode + Encode + Debug + From + Into, - ModuleError: Decode + Encode + Debug, -{ - /// Converts a numerical value `u32` into an `Error`. - /// - /// This is used to reconstruct and display an `Error` from its numerical representation - /// when an error is thrown. - fn from(value: u32) -> Self { - let error = RuntimeCallError::from(value); - let encoded = error.encode(); - if encoded[0] == MODULE_INDEX { - let (index, module_error) = (encoded[1], &encoded[2..]); - let data = vec![vec![index], module_error.to_vec()].concat(); - return Error::Module(decode(&data)); - } - Error::Raw(error) - } +fn decode(data: &[u8]) -> T { + T::decode(&mut &data[..]).expect("Decoding failed") } #[cfg(test)] mod test { - use pop_api::primitives::v0::Error as RuntimeCallError; + use pop_api::primitives::v0::Error as ApiError; use crate::error::{AssetsError::*, BalancesError::*, *}; - fn test_cases() -> Vec<(Error, RuntimeCallError)> - { + fn test_cases() -> Vec<(Error, ApiError)> { use frame_support::traits::PalletInfoAccess; use pop_api::primitives::{ArithmeticError::*, TokenError::*}; use crate::mock::RuntimeError::*; vec![ - (Error::Raw(RuntimeCallError::BadOrigin), RuntimeCallError::BadOrigin), - ( - Error::Raw(RuntimeCallError::Token(BelowMinimum)), - RuntimeCallError::Token(BelowMinimum), - ), - ( - Error::Raw(RuntimeCallError::Arithmetic(Overflow)), - RuntimeCallError::Arithmetic(Overflow), - ), + (Error::Raw(ApiError::BadOrigin), ApiError::BadOrigin), + (Error::Raw(ApiError::Token(BelowMinimum)), ApiError::Token(BelowMinimum)), + (Error::Raw(ApiError::Arithmetic(Overflow)), ApiError::Arithmetic(Overflow)), ( Error::Module(Assets(BalanceLow)), - RuntimeCallError::Module { - index: crate::mock::Assets::index() as u8, - error: [0, 0], - }, + ApiError::Module { index: crate::mock::Assets::index() as u8, error: [0, 0] }, ), ( Error::Module(Assets(NoAccount)), - RuntimeCallError::Module { - index: crate::mock::Assets::index() as u8, - error: [1, 0], - }, + ApiError::Module { index: crate::mock::Assets::index() as u8, error: [1, 0] }, ), ( Error::Module(Balances(VestingBalance)), - RuntimeCallError::Module { - index: crate::mock::Balances::index() as u8, - error: [0, 0], - }, + ApiError::Module { index: crate::mock::Balances::index() as u8, error: [0, 0] }, ), ( Error::Module(Balances(LiquidityRestrictions)), - RuntimeCallError::Module { - index: crate::mock::Balances::index() as u8, - error: [1, 0], - }, + ApiError::Module { index: crate::mock::Balances::index() as u8, error: [1, 0] }, ), ] } diff --git a/crates/pop-drink/src/lib.rs b/crates/pop-drink/src/lib.rs index ab24098..5c20ee4 100644 --- a/crates/pop-drink/src/lib.rs +++ b/crates/pop-drink/src/lib.rs @@ -1,3 +1,5 @@ +//! A library for testing smart contracts on Pop Network. + pub use drink::*; pub use frame_support::{self, assert_ok}; pub use ink_sandbox::api::assets_api::AssetsAPI; @@ -6,29 +8,30 @@ use scale::Decode; pub use session::{error::SessionError, ContractBundle, Session, NO_SALT}; pub use sp_io::TestExternalities; +/// Error type and utilities for testing contracts using the Pop API. pub mod error; #[cfg(test)] mod mock; +/// Types and utilities for testing smart contracts interacting with Pop Network Devnet via the pop +/// api. pub mod devnet { pub use pop_runtime_devnet::Runtime; use super::*; + pub use crate::error::*; - /// A set of primitive runtime errors and versioned runtime errors used for testing. + /// Error related utilities for smart contracts using pop api. pub mod error { pub use pop_runtime_devnet::RuntimeError::*; pub use crate::error::*; - /// A collection of error types from the `v0` module used for smart contract testing in the - /// `devnet` environment. pub mod v0 { - pub use pop_api::primitives::v0::{Error as RuntimeCallError, *}; + pub use pop_api::primitives::v0::{self, *}; - /// Error type for testing contracts using the API V0. - pub type Error = - crate::error::Error; + /// Error type for writing tests (see `error` module). + pub type Error = crate::error::Error; } } @@ -36,61 +39,39 @@ pub mod devnet { pub type Balance = BalanceFor; pub type AccountId = AccountIdFor; - /// This is used to resolve type mismatches between the `AccountId` in the quasi testing - /// environment and the contract environment. + /// Converts an AccountId from Pop's runtime to the account ID used in the contract environment. pub fn account_id_from_slice(s: &AccountId) -> pop_api::primitives::AccountId { let account: [u8; 32] = s.clone().into(); super::account_id_from_slice(&account) } } -/// Deploys a contract with a given constructor method, arguments, salt and an initial value. In +/// Deploy a contract with a given constructor, arguments, salt and an initial value. In /// case of success, returns the address of the deployed contract. /// -/// # Generic Parameters -/// -/// - `S` - [`Sandbox`](https://github.com/r0gue-io/pop-drink/blob/main/crates/ink-sandbox/src/lib.rs) -/// environment for the Pop Network runtime. -/// - `E` - Decodable error type returned if the contract deployment fails. -/// -/// # Parameters -/// -/// - `session` - Wrapper around Sandbox that provides methods to interact with multiple contracts. [Reference](https://github.com/r0gue-io/pop-drink/blob/main/crates/drink/drink/src/session.rs). -/// - `bundle` - A struct representing the result of parsing a `.contract` bundle file. [Reference](https://github.com/r0gue-io/pop-drink/blob/main/crates/drink/drink/src/session/bundle.rs). -/// - `method` - The name of the contract constructor method. For trait methods, use -/// `trait_name::method_name` (e.g., `Psp22::transfer`). -/// - `input` - Arguments passed to the constructor method. -/// - `salt` - Additional data used to influence the contract deployment address. -/// - `init_value` - Initial funds allocated for the contract. Requires the contract method to be -/// `payable`. +/// # Generic Parameters: +/// - `S` - Sandbox environment. +/// - `E` - `Err()` type returned by the contract. /// -/// # Examples +/// # Parameters: +/// - `session` - The session for interacting with contracts. +/// - `bundle` - The contract bundle. +/// - `method` - The name of the constructor method. +/// - `input` - The input arguments. +/// - `salt` - Optional deployment salt. +/// - `init_value` - Initial balance to transfer during the contract creation. Requires the contract +/// method to be `payable`. /// +/// # Example: /// ```rs -/// /// The contract bundle provider. -/// #[drink::contract_bundle_provider] -/// enum BundleProvider {} -/// -/// /// Sandbox environment for Pop Devnet Runtime. -/// pub struct Pop { -/// ext: TestExternalities, -/// } -/// -/// // Implement core functionalities for the `Pop` sandbox. -/// drink::impl_sandbox!(Pop, Runtime, ALICE); -/// /// #[drink::test(sandbox = Pop)] -/// fn test_constructor_works() { -/// let local_contract = BundleProvider::local().unwrap(); -/// // Contract address is returned if a deployment succeeds. -/// let contract = deploy( -/// &mut session, -/// local_contract, -/// "new", -/// vec![TOKEN.to_string(), MIN_BALANCE.to_string()], -/// vec![], -/// None -/// ).unwrap(); +/// fn test_constructor_works(mut session: Session) { +/// let bundle = BundleProvider::local().unwrap(); +/// +/// // Deploy contract. +/// // +/// // `ContractError` is the error type used by the contract. +/// assert_ok!(deploy(&mut session, bundle, "new", input, salt, init_value)); /// } /// ``` pub fn deploy( @@ -115,48 +96,36 @@ where Ok(result.unwrap()) } -/// Call a contract method and decode the returned data. -/// -/// # Generic Parameters -/// -/// - `S` - [`Sandbox`](https://github.com/r0gue-io/pop-drink/blob/main/crates/ink-sandbox/src/lib.rs) -/// environment for the Pop Network runtime. -/// - `O` - Decodable output type returned if the contract execution succeeds. -/// - `E` - Decodable error type returned if the contract execution fails. -/// -/// # Parameters -/// -/// - `session` - Wrapper around Sandbox that provides methods to interact with multiple contracts. [Reference](https://github.com/r0gue-io/pop-drink/blob/main/crates/drink/drink/src/session.rs). -/// - `func_name`: The name of the contract method. For trait methods, use `trait_name::method_name` -/// (e.g., `Psp22::transfer`). -/// - `input` - Arguments passed to the contract method. -/// - `endowment` - Funds allocated for the contract execution. Requires the contract method to be +/// Call a method and decode the returned data. +/// +/// # Generic Parameters: +/// - `S` - Sandbox environment. +/// - `O` - `Ok()` type returned by the contract. +/// - `E` - `Err()` type returned by the contract. +/// +/// # Parameters: +/// - `session` - The session for interacting with contracts. +/// - `func_name`: The name of the contract method. +/// - `input` - The input arguments. +/// - `init_value` - Balance to transfer during the call. Requires the contract method to be /// `payable`. /// -/// # Examples -/// +/// # Example: /// ```rs -/// /// The contract bundle provider. -/// #[drink::contract_bundle_provider] -/// enum BundleProvider {} -/// -/// /// Sandbox environment for Pop Devnet Runtime. -/// pub struct Pop { -/// ext: TestExternalities, -/// } -/// -/// // Implement core functionalities for the `Pop` sandbox. -/// drink::impl_sandbox!(Pop, Runtime, ALICE); -/// -/// /// Call to a contract method `Psp22::transfer` and return error `PSP22Error` if fails. -/// fn transfer(session: &mut Session, to: AccountId, amount: Balance) -> Result<(), PSP22Error> { -/// // Convert empty array into string. -/// let empty_array = serde_json::to_string::<[u8; 0]>(&[]).unwrap(); -/// call::( +/// #[drink::test(sandbox = Pop)] +/// fn call_works(mut session: Session) { +/// let bundle = BundleProvider::local().unwrap(); +/// assert_ok!(deploy(&mut session, bundle, "new", input, salt, init_value)); +/// +/// // Call contract. +/// // +/// // `()` is the successful result type used by the contract. +/// // `ContractError` is the error type used by the contract. +/// call::( /// session, -/// "Psp22::transfer", -/// vec![to.to_string(), amount.to_string(), empty_array], -/// None, +/// "transfer", +/// input, +/// init_value, /// ) /// } /// ``` @@ -187,32 +156,22 @@ where } } -fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId { - pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") -} - -/// Get the last event from pallet contracts. +/// Get the last contract event. /// -/// # Generic Parameters +/// # Generic Parameters: +/// - `S` - Sandbox environment. /// -/// - `S` - [`Sandbox`](https://github.com/r0gue-io/pop-drink/blob/main/crates/ink-sandbox/src/lib.rs) -/// environment for the Pop Network runtime. -/// -/// # Parameters -/// -/// - `session` - Wrapper around Sandbox that provides methods to interact with multiple contracts. [Reference](https://github.com/r0gue-io/pop-drink/blob/main/crates/drink/drink/src/session.rs). -/// -/// # Examples +/// # Parameters: +/// - `session` - The session for interacting with contracts. /// +/// # Example: /// ```rs -/// use drink::{assert_ok, devnet::account_id_from_slice, last_contract_event}; +/// use drink::last_contract_event; /// /// assert_eq!( -/// last_contract_event(&session).unwrap(), -/// Transfer { -/// from: Some(account_id_from_slice(&ALICE)), -/// to: Some(account_id_from_slice(&BOB)), -/// value, +/// last_contract_event::(&session).unwrap(), +/// ContractEvent { +/// value: 42, /// } /// .encode() /// .as_slice() @@ -227,3 +186,7 @@ where { session.record().last_event_batch().contract_events().last().cloned() } + +fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId { + pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") +}