From 0771634f53e83d65ceecf1d03639d58a9b69b902 Mon Sep 17 00:00:00 2001 From: sergiuosvat Date: Thu, 22 Aug 2024 11:49:10 +0300 Subject: [PATCH 1/3] add potlock contract --- Cargo.lock | 39 + Cargo.toml | 3 + .../scenarios/wrong-start-params.scen.json | 25 + contracts/potlock/Cargo.toml | 22 + contracts/potlock/README.md | 27 + contracts/potlock/interact-rs/.gitignore | 2 + contracts/potlock/interact-rs/Cargo.toml | 30 + contracts/potlock/interact-rs/config.toml | 6 + .../src/potlock_interactor_config.rs | 32 + .../src/potlock_interactor_main.rs | 565 ++++++++++ contracts/potlock/interact-rs/src/proxy.rs | 390 +++++++ contracts/potlock/interact-rs/state.toml | 1 + contracts/potlock/meta/Cargo.toml | 12 + contracts/potlock/meta/src/main.rs | 3 + contracts/potlock/multiversx.json | 3 + contracts/potlock/output/potlock.abi.json | 419 ++++++++ contracts/potlock/output/potlock.imports.json | 36 + contracts/potlock/output/potlock.mxsc.json | 470 +++++++++ contracts/potlock/output/potlock.wasm | Bin 0 -> 12628 bytes contracts/potlock/sc-config.toml | 4 + contracts/potlock/src/potlock.rs | 29 + .../potlock/src/potlock_admin_interactions.rs | 132 +++ contracts/potlock/src/potlock_interactions.rs | 106 ++ contracts/potlock/src/potlock_requirements.rs | 69 ++ contracts/potlock/src/potlock_storage.rs | 103 ++ .../potlock/tests/potlock_blackbox_tests.rs | 979 ++++++++++++++++++ contracts/potlock/tests/potlock_proxy.rs | 390 +++++++ contracts/potlock/wasm/Cargo.lock | 198 ++++ contracts/potlock/wasm/Cargo.toml | 34 + contracts/potlock/wasm/src/lib.rs | 47 + 30 files changed, 4176 insertions(+) create mode 100644 contracts/potlock/Cargo.toml create mode 100644 contracts/potlock/README.md create mode 100644 contracts/potlock/interact-rs/.gitignore create mode 100644 contracts/potlock/interact-rs/Cargo.toml create mode 100644 contracts/potlock/interact-rs/config.toml create mode 100644 contracts/potlock/interact-rs/src/potlock_interactor_config.rs create mode 100644 contracts/potlock/interact-rs/src/potlock_interactor_main.rs create mode 100644 contracts/potlock/interact-rs/src/proxy.rs create mode 100644 contracts/potlock/interact-rs/state.toml create mode 100644 contracts/potlock/meta/Cargo.toml create mode 100644 contracts/potlock/meta/src/main.rs create mode 100644 contracts/potlock/multiversx.json create mode 100644 contracts/potlock/output/potlock.abi.json create mode 100644 contracts/potlock/output/potlock.imports.json create mode 100644 contracts/potlock/output/potlock.mxsc.json create mode 100644 contracts/potlock/output/potlock.wasm create mode 100644 contracts/potlock/sc-config.toml create mode 100644 contracts/potlock/src/potlock.rs create mode 100644 contracts/potlock/src/potlock_admin_interactions.rs create mode 100644 contracts/potlock/src/potlock_interactions.rs create mode 100644 contracts/potlock/src/potlock_requirements.rs create mode 100644 contracts/potlock/src/potlock_storage.rs create mode 100644 contracts/potlock/tests/potlock_blackbox_tests.rs create mode 100644 contracts/potlock/tests/potlock_proxy.rs create mode 100644 contracts/potlock/wasm/Cargo.lock create mode 100644 contracts/potlock/wasm/Cargo.toml create mode 100644 contracts/potlock/wasm/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index b2f60d3..6810148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1037,6 +1037,15 @@ dependencies = [ "wasmprinter", ] +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "multiversx-sc-scenario" version = "0.52.3" @@ -1318,6 +1327,24 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "potlock" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "potlock-meta" +version = "0.0.0" +dependencies = [ + "multiversx-sc-meta-lib", + "potlock", +] + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1532,6 +1559,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rust-interact" +version = "0.0.0" +dependencies = [ + "clap", + "multiversx-sc", + "multiversx-sc-snippets", + "potlock", + "serde", + "toml", +] + [[package]] name = "rust-interact-lottery-esdt" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index dafe850..3588d5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,7 @@ members = [ "contracts/lottery-esdt", "contracts/lottery-esdt/meta", "contracts/lottery-esdt/interactor", + "contracts/potlock", + "contracts/potlock/meta", + "contracts/potlock/interact-rs", ] \ No newline at end of file diff --git a/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json b/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json index 1e12a98..1864db6 100644 --- a/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json +++ b/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json @@ -346,6 +346,31 @@ "status": "4", "message": "str:The contract can't burn the selected token!" } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:OWNER_ADDRESS", + "to": "sc:lottery-esdt", + "function": "start", + "arguments": [ + "0x74657374", + "0x544553542d313233343536", + "0x01", + "0x0100000002", + "0x010000000000000014", + "0x0100000001", + "0x01000000024b19", + "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x65" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "status": "4", + "message": "str:Invalid burn percentage!" + } } ] } diff --git a/contracts/potlock/Cargo.toml b/contracts/potlock/Cargo.toml new file mode 100644 index 0000000..783b1e4 --- /dev/null +++ b/contracts/potlock/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "potlock" +version = "0.0.0" +authors = ["you"] +edition = "2021" +publish = false +readme = "README.md" + +[lib] +path = "src/potlock.rs" + +[dependencies.multiversx-sc] +version = "0.52.3" + +[dependencies.multiversx-sc-modules] +version = "=0.52.3" + +[dev-dependencies] +num-bigint = "0.4.2" + +[dev-dependencies.multiversx-sc-scenario] +version = "0.52.3" diff --git a/contracts/potlock/README.md b/contracts/potlock/README.md new file mode 100644 index 0000000..f13a60f --- /dev/null +++ b/contracts/potlock/README.md @@ -0,0 +1,27 @@ +# Potlock SC + +## Overview +Potlock is a smart contract designed to enhance and accelerate Public Goods Funding (PGF) by leveraging the power of blockchain technology. Inspired by the collaboration between Potlock and the NEAR Foundation, this contract aims to provide an efficient and transparent mechanism for funding public goods, encouraging community participation, and maximizing the impact of pooled resources. + +## Features +* **Public Goods Funding (PGF)**: Facilitates the pooling of resources for funding projects that benefit the public. +* **Transparent Allocation**: Ensures that funds are distributed transparently according to predefined rules. +* **Decentralized Governance:** Empowers the community to participate in decision-making processes related to fund allocation. +* **Efficient Fund Management**: Optimizes the management and distribution of funds to maximize impact. + + + +## How It Works + +2. **Activation**: +* A POT is defined, where backers and the foundation contribute tokens. +* Anyone can suggest a new POT by paying a fee, but the proposal must be accepted by the admin for it to be activated. +2. **Application and Review**: +* Projects submit their applications to the POT, aiming to secure funding. +* An authority reviews these submissions, evaluating their eligibility and potential impact. +3. **Donation and Matching**: +* Approved projects receive direct contributions from verified donors. +* These donations are further amplified by the POT's value through the Quadratic Funding (QF) model, maximizing the impact of smaller contributions. +4. **Payout**: +* Funds are distributed to the projects based on the matching model. +* After a cooldown period, the process can start again from step 1, with a new or existing POT. \ No newline at end of file diff --git a/contracts/potlock/interact-rs/.gitignore b/contracts/potlock/interact-rs/.gitignore new file mode 100644 index 0000000..5a64d09 --- /dev/null +++ b/contracts/potlock/interact-rs/.gitignore @@ -0,0 +1,2 @@ +# Pem files are used for interactions, but shouldn't be committed +*.pem diff --git a/contracts/potlock/interact-rs/Cargo.toml b/contracts/potlock/interact-rs/Cargo.toml new file mode 100644 index 0000000..e0cb932 --- /dev/null +++ b/contracts/potlock/interact-rs/Cargo.toml @@ -0,0 +1,30 @@ +[[bin]] +name = "rust-interact" +path = "src/potlock_interactor_main.rs" + +[package] +name = "rust-interact" +version = "0.0.0" +authors = ["you"] +edition = "2021" +publish = false + +[dependencies] +toml = "0.8.6" + +[dependencies.potlock] +path = ".." + +[dependencies.multiversx-sc-snippets] +version = "0.52.3" + +[dependencies.multiversx-sc] +version = "0.52.3" + +[dependencies.clap] +version = "4.4.7" +features = ["derive"] + +[dependencies.serde] +version = "1.0" +features = ["derive"] diff --git a/contracts/potlock/interact-rs/config.toml b/contracts/potlock/interact-rs/config.toml new file mode 100644 index 0000000..dbbe25d --- /dev/null +++ b/contracts/potlock/interact-rs/config.toml @@ -0,0 +1,6 @@ +gateway = 'https://devnet-gateway.multiversx.com' +admin = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" +pot_proposer = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" +project_proposer = "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" +pot_donor = "erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7" +project_donor = "erd18tudnj2z8vjh0339yu3vrkgzz2jpz8mjq0uhgnmklnap6z33qqeszq2yn4" \ No newline at end of file diff --git a/contracts/potlock/interact-rs/src/potlock_interactor_config.rs b/contracts/potlock/interact-rs/src/potlock_interactor_config.rs new file mode 100644 index 0000000..77a3476 --- /dev/null +++ b/contracts/potlock/interact-rs/src/potlock_interactor_config.rs @@ -0,0 +1,32 @@ +use multiversx_sc_snippets::imports::Bech32Address; +use serde::Deserialize; +use std::io::Read; + +/// Config file +const CONFIG_FILE: &str = "config.toml"; + +/// Multisig Interact configuration +#[derive(Debug, Deserialize)] +pub struct Config { + gateway: String, + pub admin: Bech32Address, + pub pot_proposer: Bech32Address, + pub project_proposer: Bech32Address, + pub pot_donor: Bech32Address, + pub project_donor: Bech32Address, +} + +impl Config { + // Deserializes config from file + pub fn load_config() -> Self { + let mut file = std::fs::File::open(CONFIG_FILE).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + toml::from_str(&content).unwrap() + } + + // Returns the gateway + pub fn gateway(&self) -> &str { + &self.gateway + } +} diff --git a/contracts/potlock/interact-rs/src/potlock_interactor_main.rs b/contracts/potlock/interact-rs/src/potlock_interactor_main.rs new file mode 100644 index 0000000..85eba28 --- /dev/null +++ b/contracts/potlock/interact-rs/src/potlock_interactor_main.rs @@ -0,0 +1,565 @@ +#![allow(non_snake_case)] + +mod proxy; + +use multiversx_sc_snippets::imports::*; +use multiversx_sc_snippets::sdk; +use serde::{Deserialize, Serialize}; +use std::{ + io::{Read, Write}, + path::Path, +}; + +const GATEWAY: &str = sdk::gateway::DEVNET_GATEWAY; +const STATE_FILE: &str = "state.toml"; + +#[tokio::main] +async fn main() { + env_logger::init(); + + let mut args = std::env::args(); + let _ = args.next(); + let cmd = args.next().expect("at least one argument required"); + let mut interact = ContractInteract::new().await; + match cmd.as_str() { + "deploy" => interact.deploy().await, + "upgrade" => interact.upgrade().await, + "changeFeeForPots" => interact.change_fee_for_pots().await, + "acceptPot" => interact.accept_pot().await, + "removePot" => interact.remove_pot().await, + "acceptApplication" => interact.accept_application().await, + "removeApplication" => interact.remove_application().await, + "rejectDonation" => interact.reject_donation().await, + "distributePotToProjects" => interact.distribute_pot_to_projects().await, + "addPot" => interact.add_pot().await, + "applyForPot" => interact.apply_for_pot().await, + "donateToPot" => interact.donate_to_pot().await, + "donateToProject" => interact.donate_to_project().await, + "getFeeTokenIdentifier" => interact.fee_token_identifier().await, + "getFeeAmount" => interact.fee_amount().await, + "getPotlocks" => interact.potlocks().await, + "getProjects" => interact.projects().await, + "potDonations" => interact.pot_donations().await, + "projectDonations" => interact.project_donations().await, + "isAdmin" => interact.is_admin().await, + "addAdmin" => interact.add_admin().await, + "removeAdmin" => interact.remove_admin().await, + "getAdmins" => interact.admins().await, + _ => panic!("unknown command: {}", &cmd), + } +} + +#[derive(Debug, Default, Serialize, Deserialize)] +struct State { + contract_address: Option, +} + +impl State { + // Deserializes state from file + pub fn load_state() -> Self { + if Path::new(STATE_FILE).exists() { + let mut file = std::fs::File::open(STATE_FILE).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + toml::from_str(&content).unwrap() + } else { + Self::default() + } + } + + /// Sets the contract address + pub fn set_address(&mut self, address: Bech32Address) { + self.contract_address = Some(address); + } + + /// Returns the contract address + pub fn current_address(&self) -> &Bech32Address { + self.contract_address + .as_ref() + .expect("no known contract, deploy first") + } +} + +impl Drop for State { + // Serializes state to file + fn drop(&mut self) { + let mut file = std::fs::File::create(STATE_FILE).unwrap(); + file.write_all(toml::to_string(self).unwrap().as_bytes()) + .unwrap(); + } +} + +struct ContractInteract { + interactor: Interactor, + wallet_address: Address, + contract_code: BytesValue, + state: State, +} + +impl ContractInteract { + async fn new() -> Self { + let mut interactor = Interactor::new(GATEWAY).await; + let wallet_address = interactor.register_wallet(test_wallets::alice()); + + let contract_code = BytesValue::interpret_from( + "mxsc:../output/potlock.mxsc.json", + &InterpreterContext::default(), + ); + + ContractInteract { + interactor, + wallet_address, + contract_code, + state: State::load_state(), + } + } + + async fn deploy(&mut self) { + let admins = MultiValueVec::from(vec![bech32::decode("")]); + + let new_address = self + .interactor + .tx() + .from(&self.wallet_address) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .init(admins) + .code(&self.contract_code) + .returns(ReturnsNewAddress) + .prepare_async() + .run() + .await; + let new_address_bech32 = bech32::encode(&new_address); + self.state.set_address(Bech32Address::from_bech32_string( + new_address_bech32.clone(), + )); + + println!("new address: {new_address_bech32}"); + } + + async fn upgrade(&mut self) { + let response = self + .interactor + .tx() + .to(self.state.current_address()) + .from(&self.wallet_address) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .upgrade() + .code(&self.contract_code) + .code_metadata(CodeMetadata::UPGRADEABLE) + .returns(ReturnsNewAddress) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn change_fee_for_pots(&mut self) { + let token_identifier = TokenIdentifier::from_esdt_bytes(&b""[..]); + let fee = BigUint::::from(0u128); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .change_fee_for_pots(token_identifier, fee) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn accept_pot(&mut self) { + let potlock_id = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .accept_pot(potlock_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn remove_pot(&mut self) { + let potlock_id = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .remove_pot(potlock_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn accept_application(&mut self) { + let project_id = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .accept_application(project_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn remove_application(&mut self) { + let project_id = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .remove_application(project_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn reject_donation(&mut self) { + let potlock_id = 0u32; + let user = bech32::decode(""); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .reject_donation(potlock_id, user) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn distribute_pot_to_projects(&mut self) { + let potlock_id = 0u32; + let project_percentages = + MultiValueVec::from(vec![MultiValue2::::from((0u32, 0u64))]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .distribute_pot_to_projects(potlock_id, project_percentages) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn add_pot(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let name = ManagedBuffer::new_from_bytes(&b""[..]); + let description = ManagedBuffer::new_from_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .add_pot(name, description) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn apply_for_pot(&mut self) { + let potlock_id = 0u32; + let project_name = ManagedBuffer::new_from_bytes(&b""[..]); + let description = ManagedBuffer::new_from_bytes(&b""[..]); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .apply_for_pot(potlock_id, project_name, description) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn donate_to_pot(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let potlock_id = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .donate_to_pot(potlock_id) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn donate_to_project(&mut self) { + let token_id = String::new(); + let token_nonce = 0u64; + let token_amount = BigUint::::from(0u128); + + let project_id = 0u32; + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .donate_to_project(project_id) + .payment(( + TokenIdentifier::from(token_id.as_str()), + token_nonce, + token_amount, + )) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn fee_token_identifier(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .fee_token_identifier() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn fee_amount(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .fee_amount() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn potlocks(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .potlocks() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn projects(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .projects() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn pot_donations(&mut self) { + let potlock_id = 0u32; + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .pot_donations(potlock_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn project_donations(&mut self) { + let project_id = 0u32; + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .project_donations(project_id) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn is_admin(&mut self) { + let address = bech32::decode(""); + + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .is_admin(address) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } + + async fn add_admin(&mut self) { + let address = bech32::decode(""); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .add_admin(address) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn remove_admin(&mut self) { + let address = bech32::decode(""); + + let response = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_address()) + .gas(30_000_000u64) + .typed(proxy::PotlockProxy) + .remove_admin(address) + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {response:?}"); + } + + async fn admins(&mut self) { + let result_value = self + .interactor + .query() + .to(self.state.current_address()) + .typed(proxy::PotlockProxy) + .admins() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + println!("Result: {result_value:?}"); + } +} diff --git a/contracts/potlock/interact-rs/src/proxy.rs b/contracts/potlock/interact-rs/src/proxy.rs new file mode 100644 index 0000000..7abb266 --- /dev/null +++ b/contracts/potlock/interact-rs/src/proxy.rs @@ -0,0 +1,390 @@ +// Code generated by the multiversx-sc proxy generator. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +#![allow(dead_code)] +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct PotlockProxy; + +impl TxProxyTrait for PotlockProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PotlockProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PotlockProxyMethods { wrapped_tx: tx } + } +} + +pub struct PotlockProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PotlockProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + admins: Arg0, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&admins) + .original_result() + } +} + +#[rustfmt::skip] +impl PotlockProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl PotlockProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn change_fee_for_pots< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_identifier: Arg0, + fee: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeFeeForPots") + .argument(&token_identifier) + .argument(&fee) + .original_result() + } + + pub fn accept_pot< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("acceptPot") + .argument(&potlock_id) + .original_result() + } + + pub fn remove_pot< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removePot") + .argument(&potlock_id) + .original_result() + } + + pub fn accept_application< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("acceptApplication") + .argument(&project_id) + .original_result() + } + + pub fn remove_application< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeApplication") + .argument(&project_id) + .original_result() + } + + pub fn reject_donation< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + potlock_id: Arg0, + user: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("rejectDonation") + .argument(&potlock_id) + .argument(&user) + .original_result() + } + + pub fn distribute_pot_to_projects< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + potlock_id: Arg0, + project_percentages: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributePotToProjects") + .argument(&potlock_id) + .argument(&project_percentages) + .original_result() + } + + pub fn add_pot< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + name: Arg0, + description: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addPot") + .argument(&name) + .argument(&description) + .original_result() + } + + pub fn apply_for_pot< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + potlock_id: Arg0, + project_name: Arg1, + description: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("applyForPot") + .argument(&potlock_id) + .argument(&project_name) + .argument(&description) + .original_result() + } + + pub fn donate_to_pot< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("donateToPot") + .argument(&potlock_id) + .original_result() + } + + pub fn donate_to_project< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("donateToProject") + .argument(&project_id) + .original_result() + } + + pub fn fee_token_identifier( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeTokenIdentifier") + .original_result() + } + + pub fn fee_amount( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeAmount") + .original_result() + } + + pub fn potlocks( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPotlocks") + .original_result() + } + + pub fn projects( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getProjects") + .original_result() + } + + pub fn pot_donations< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall, EsdtTokenPayment>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("potDonations") + .argument(&potlock_id) + .original_result() + } + + pub fn project_donations< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall, EsdtTokenPayment>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("projectDonations") + .argument(&project_id) + .original_result() + } + + pub fn is_admin< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isAdmin") + .argument(&address) + .original_result() + } + + pub fn add_admin< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addAdmin") + .argument(&address) + .original_result() + } + + pub fn remove_admin< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeAdmin") + .argument(&address) + .original_result() + } + + pub fn admins( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAdmins") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Debug)] +pub struct Pot +where + Api: ManagedTypeApi, +{ + pub potlock_id: usize, + pub proposer: ManagedAddress, + pub token_identifier: TokenIdentifier, + pub fee: BigUint, + pub name: ManagedBuffer, + pub description: ManagedBuffer, + pub status: Status, +} + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedDecode, NestedEncode, Debug)] +pub enum Status { + Inactive, + Active, +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Debug)] +pub struct Project +where + Api: ManagedTypeApi, +{ + pub potlock_id: usize, + pub name: ManagedBuffer, + pub description: ManagedBuffer, + pub owner: ManagedAddress, + pub status: Status, +} diff --git a/contracts/potlock/interact-rs/state.toml b/contracts/potlock/interact-rs/state.toml new file mode 100644 index 0000000..6a70e4c --- /dev/null +++ b/contracts/potlock/interact-rs/state.toml @@ -0,0 +1 @@ +contract_address = "erd1qqqqqqqqqqqqqpgq5upecnmqrjd673jhuy36z7ehdgsgkkuvd8ssdxdcaq" diff --git a/contracts/potlock/meta/Cargo.toml b/contracts/potlock/meta/Cargo.toml new file mode 100644 index 0000000..0ac1e44 --- /dev/null +++ b/contracts/potlock/meta/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "potlock-meta" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies.potlock] +path = ".." + +[dependencies.multiversx-sc-meta-lib] +version = "0.52.3" +default-features = false diff --git a/contracts/potlock/meta/src/main.rs b/contracts/potlock/meta/src/main.rs new file mode 100644 index 0000000..1514f0f --- /dev/null +++ b/contracts/potlock/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta_lib::cli_main::(); +} diff --git a/contracts/potlock/multiversx.json b/contracts/potlock/multiversx.json new file mode 100644 index 0000000..7365539 --- /dev/null +++ b/contracts/potlock/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/contracts/potlock/output/potlock.abi.json b/contracts/potlock/output/potlock.abi.json new file mode 100644 index 0000000..90b53bf --- /dev/null +++ b/contracts/potlock/output/potlock.abi.json @@ -0,0 +1,419 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.79.0", + "commitHash": "129f3b9964af4d4a709d1383930ade12dfe7c081", + "commitDate": "2024-06-10", + "channel": "Stable", + "short": "rustc 1.79.0 (129f3b996 2024-06-10)" + }, + "contractCrate": { + "name": "potlock", + "version": "0.0.0", + "gitVersion": "v0.45.2.1-reproducible-388-g906e146" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.52.3" + } + }, + "name": "Potlock", + "constructor": { + "inputs": [ + { + "name": "admins", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + "upgradeConstructor": { + "inputs": [], + "outputs": [] + }, + "endpoints": [ + { + "name": "changeFeeForPots", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "fee", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "acceptPot", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "removePot", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "acceptApplication", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "removeApplication", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "rejectDonation", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "user", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "distributePotToProjects", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "project_percentages", + "type": "variadic>", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "addPot", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [ + { + "name": "name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "applyForPot", + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "project_name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "donateToPot", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "donateToProject", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "getFeeTokenIdentifier", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "TokenIdentifier" + } + ] + }, + { + "name": "getFeeAmount", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "getPotlocks", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "getProjects", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "potDonations", + "mutability": "readonly", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "projectDonations", + "mutability": "readonly", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "isAdmin", + "mutability": "readonly", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "addAdmin", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "removeAdmin", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "getAdmins", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic
", + "multi_result": true + } + ] + } + ], + "esdtAttributes": [], + "hasCallback": false, + "types": { + "EsdtTokenPayment": { + "type": "struct", + "fields": [ + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "amount", + "type": "BigUint" + } + ] + }, + "Pot": { + "type": "struct", + "fields": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "proposer", + "type": "Address" + }, + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "fee", + "type": "BigUint" + }, + { + "name": "name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + }, + { + "name": "status", + "type": "Status" + } + ] + }, + "Project": { + "type": "struct", + "fields": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + }, + { + "name": "owner", + "type": "Address" + }, + { + "name": "status", + "type": "Status" + } + ] + }, + "Status": { + "type": "enum", + "variants": [ + { + "name": "Inactive", + "discriminant": 0 + }, + { + "name": "Active", + "discriminant": 1 + } + ] + } + } +} diff --git a/contracts/potlock/output/potlock.imports.json b/contracts/potlock/output/potlock.imports.json new file mode 100644 index 0000000..015532e --- /dev/null +++ b/contracts/potlock/output/potlock.imports.json @@ -0,0 +1,36 @@ +[ + "bigIntAdd", + "bigIntCmp", + "bigIntFinishUnsigned", + "bigIntGetUnsignedArgument", + "bigIntMul", + "bigIntSetInt64", + "bigIntSign", + "bigIntTDiv", + "checkNoPayment", + "getNumArguments", + "mBufferAppend", + "mBufferAppendBytes", + "mBufferCopyByteSlice", + "mBufferEq", + "mBufferFinish", + "mBufferFromBigIntUnsigned", + "mBufferGetArgument", + "mBufferGetByteSlice", + "mBufferGetLength", + "mBufferNew", + "mBufferSetBytes", + "mBufferStorageLoad", + "mBufferStorageStore", + "mBufferToBigIntUnsigned", + "managedCaller", + "managedGetMultiESDTCallValue", + "managedMultiTransferESDTNFTExecute", + "managedOwnerAddress", + "managedSignalError", + "signalError", + "smallIntFinishSigned", + "smallIntFinishUnsigned", + "smallIntGetUnsignedArgument", + "validateTokenIdentifier" +] \ No newline at end of file diff --git a/contracts/potlock/output/potlock.mxsc.json b/contracts/potlock/output/potlock.mxsc.json new file mode 100644 index 0000000..0318e4a --- /dev/null +++ b/contracts/potlock/output/potlock.mxsc.json @@ -0,0 +1,470 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.79.0", + "commitHash": "129f3b9964af4d4a709d1383930ade12dfe7c081", + "commitDate": "2024-06-10", + "channel": "Stable", + "short": "rustc 1.79.0 (129f3b996 2024-06-10)" + }, + "contractCrate": { + "name": "potlock", + "version": "0.0.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.52.3" + } + }, + "abi": { + "name": "Potlock", + "constructor": { + "inputs": [ + { + "name": "admins", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + "upgradeConstructor": { + "inputs": [], + "outputs": [] + }, + "endpoints": [ + { + "name": "changeFeeForPots", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "fee", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "acceptPot", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "removePot", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "acceptApplication", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "removeApplication", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "rejectDonation", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "user", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "distributePotToProjects", + "onlyAdmin": true, + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "project_percentages", + "type": "variadic>", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "addPot", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [ + { + "name": "name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + } + ], + "outputs": [] + }, + { + "name": "applyForPot", + "mutability": "mutable", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "project_name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "donateToPot", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "donateToProject", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "getFeeTokenIdentifier", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "TokenIdentifier" + } + ] + }, + { + "name": "getFeeAmount", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "getPotlocks", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "getProjects", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "potDonations", + "mutability": "readonly", + "inputs": [ + { + "name": "potlock_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "projectDonations", + "mutability": "readonly", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "variadic>", + "multi_result": true + } + ] + }, + { + "name": "isAdmin", + "mutability": "readonly", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "addAdmin", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "removeAdmin", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "address", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "getAdmins", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic
", + "multi_result": true + } + ] + } + ], + "esdtAttributes": [], + "hasCallback": false, + "types": { + "EsdtTokenPayment": { + "type": "struct", + "fields": [ + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "token_nonce", + "type": "u64" + }, + { + "name": "amount", + "type": "BigUint" + } + ] + }, + "Pot": { + "type": "struct", + "fields": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "proposer", + "type": "Address" + }, + { + "name": "token_identifier", + "type": "TokenIdentifier" + }, + { + "name": "fee", + "type": "BigUint" + }, + { + "name": "name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + }, + { + "name": "status", + "type": "Status" + } + ] + }, + "Project": { + "type": "struct", + "fields": [ + { + "name": "potlock_id", + "type": "u32" + }, + { + "name": "name", + "type": "bytes" + }, + { + "name": "description", + "type": "bytes" + }, + { + "name": "owner", + "type": "Address" + }, + { + "name": "status", + "type": "Status" + } + ] + }, + "Status": { + "type": "enum", + "variants": [ + { + "name": "Inactive", + "discriminant": 0 + }, + { + "name": "Active", + "discriminant": 1 + } + ] + } + } + }, + "code": "0061736d01000000015f1160027f7f0060000060027f7f017f60017f0060017f017f60037f7f7f0060047f7f7f7f006000017f60037f7f7f017f60047f7f7f7f017f60027f7e0060017f017e60017e0060057f7f7e7f7f017f60027e7f0060017e017f60027f7f017e02b9062203656e760b7369676e616c4572726f72000003656e760a6d4275666665724e6577000703656e760d6d427566666572417070656e64000203656e76096d4275666665724571000203656e760d6d42756666657246696e697368000403656e76106d4275666665724765744c656e677468000403656e760e626967496e74536574496e743634000a03656e7609626967496e74416464000503656e76226d616e616765644d756c74695472616e73666572455344544e465445786563757465000d03656e760d6d616e6167656443616c6c6572000303656e76136d616e616765644f776e657241646472657373000303656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000303656e76126d427566666572476574417267756d656e74000203656e76126d427566666572417070656e644279746573000803656e76126d616e616765645369676e616c4572726f72000303656e7619626967496e74476574556e7369676e6564417267756d656e74000003656e761b736d616c6c496e74476574556e7369676e6564417267756d656e74000b03656e760f6765744e756d417267756d656e7473000703656e76146d427566666572436f707942797465536c696365000903656e760a626967496e745369676e000403656e76136d42756666657247657442797465536c696365000903656e760f6d4275666665725365744279746573000803656e76196d42756666657246726f6d426967496e74556e7369676e6564000203656e76176d427566666572546f426967496e74556e7369676e6564000203656e76126d42756666657253746f726167654c6f6164000203656e76136d42756666657253746f7261676553746f7265000203656e760e636865636b4e6f5061796d656e74000103656e761776616c6964617465546f6b656e4964656e746966696572000403656e7609626967496e744d756c000503656e760a626967496e7454446976000503656e7609626967496e74436d70000203656e7616736d616c6c496e7446696e697368556e7369676e6564000c03656e7614626967496e7446696e697368556e7369676e6564000303656e7614736d616c6c496e7446696e6973685369676e6564000c0391018f010206050005040200050200060702030004020204000400000004030707000607010309010406040004080303030103000e020800000f04000000000000000305030002060200060900020a050002100006020502020405060604000004000400020502020004000b01040307000007030303030303010101010101010101010101010101010101010101010101010005030100030616037f01418080080b7f004185d5080b7f004190d5080b07a2031b066d656d6f7279020004696e69740097010775706772616465009801106368616e6765466565466f72506f747300990109616363657074506f74009a010972656d6f7665506f74009b01116163636570744170706c69636174696f6e009c011172656d6f76654170706c69636174696f6e009d010e72656a656374446f6e6174696f6e009e011764697374726962757465506f74546f50726f6a65637473009f0106616464506f7400a0010b6170706c79466f72506f7400a1010b646f6e617465546f506f7400a2010f646f6e617465546f50726f6a65637400a30115676574466565546f6b656e4964656e74696669657200a4010c676574466565416d6f756e7400a5010b676574506f746c6f636b7300a6010b67657450726f6a6563747300a7010c706f74446f6e6174696f6e7300a8011070726f6a656374446f6e6174696f6e7300a90107697341646d696e00aa010861646441646d696e00ab010b72656d6f766541646d696e00ac010967657441646d696e7300ad010863616c6c4261636b00ae010a5f5f646174615f656e6403010b5f5f686561705f6261736503020adb4f8f014c01027f230041106b22022400200241003a000f20002002410f6a41012001102302400240024020022d000f0e020201000b2001418e8008410d1024000b410121030b200241106a240020030bf00301077f2000280200210702400240024002400240024020002d001045044020002802082204100522054190ce004b0d0141fcd4082d00000d0141f8d408200536020041fcd40841013a00002004410041e88608200510441a200041013a00100b200220076a220841f8d4082802004d0d010c050b200041003a0010200420072001200210440d04200220076a21080c010b200720084b0d0120084190ce004b0d02200741e886086a210320012104200241104f04402004410020046b41037122016a210620010440200321050340200420052d00003a0000200541016a2105200441016a22042006490d000b0b2006200220016b220a417c7122096a21040240200120036a22014103710440200941004c0d012001410374220241187121072001417c71220541046a2103410020026b4118712102200528020021050340200620052007762003280200220520027472360200200341046a2103200641046a22062004490d000b0c010b200941004c0d0020012103034020062003280200360200200341046a2103200641046a22062004490d000b0b200120096a2103200a41037121020b20020440200220046a21010340200420032d00003a0000200341016a2103200441016a22042001490d000b0b0b200020083602000f0b10af01000b1045000b200341938108410f1024000b2c01017f41e38108411b102f2203200010021a200341d480084103100d1a200320012002100d1a2003100e000b2d01017f230041106b220224002002200041ff01714100473a000f20012002410f6a41011026200241106a24000b0b00200020012002100d1a0b0f01017f10012201200010021a20010b0b0020002001100341004a0b5b01037f230041106b2203240020012802042202047f200341086a200128020022042802002002102a2001200328020c36020420042802002002102b210241010541000b21012000200236020420002001360200200341106a24000b800101027f230041206b220324002003410c6a2204200141c78108410b200210692201103120042001105321022003410c6a2001105321042003280210200328020c46044020032d001c044041f8d408410036020041fcd40841003a00000b2000200436020420002002360200200341206a24000f0b200141808008410e1024000b1000200041d2810841062001106910770bc90102027f027e230041306b220224002002200110290240024020022802004101460440200241186a20012802082201280200200141086a28020020022802042201102d2002290318500d02200241106a200241286a22032903002204370300200220022903202205370308200241246a200437020020002001360208200042013703002002200537021c2000200229021837020c200041146a200241206a2902003702002000411c6a20032802003602000c010b200042003703000b200241306a24000f0b10af01000b2201017e2000200120031066047e200041086a20022003106d42010542000b3703000b080041014100102f0b1101017f103e22022000200110151a20020b0700200010041a0b3101017f20011032220210052101200041003a00102000200136020c2000200236020820002001360204200041003602000b0d002000103e220010181a20000b0a0020002001103410350b0e002000200020011053200110540b0d002000103e220010171a20000b0a0020001037200110380b0f01017f103e2201200010161a20010b4f01027f230041106b22022400200220001005220341187420034180fe03714108747220034108764180fe03712003411876727236020c20012002410c6a41041026200120001055200241106a24000b0900200020011000000b870102067f017e230041206b22022400200128020c2204103b41ff0171044020012903002108200241086a103c200228020c210520022802082106103d2103200128020810272107103e22014200100620012001200410072002200136021c20022008370310200220073602182003200241106a103f200020032006200510400b200241206a24000b1300417f20001013220041004720004100481b0b1601017f103d21012000103d360204200020013602000b1101017f103e22004101410010151a20000b1901017f41e4860841e4860828020041016b220036020020000bd20102027f017e230041106b2203240020032001280208220241187420024180fe03714108747220024108764180fe0371200241187672723602002003200128020c220241187420024180fe03714108747220024108764180fe03712002411876727236020c20032001290300220442388620044280fe0383422886842004428080fc0783421886200442808080f80f834208868484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370204200020034110100d1a200341106a24000b0f002000200142002002200310081a0b0c01017f103e2200100920000b1d01017f103e2200100a20001041102804400f0b41a0860841241000000bf002020a7f017e230041106b22022400416b210302404184d5082d000022010440416b41ffffffff0720011b21030c010b4184d50841013a0000416b100b0b024020031005417071411046044041002101200310052106200241086a2107410121040340200141106a220820064b0d022007420037030020024200370300200320012002411010441a200404402002290204220b423886200b4280fe038342288684200b428080fc0783421886200b42808080f80f834208868484200b42088842808080f80f83200b421888428080fc078384200b4228884280fe0383200b423888848484210b2002280200220141187420014180fe03714108747220014108764180fe0371200141187672722109200228020c220141187420014180fe03714108747220014108764180fe037120014118767272210a4101210541002104200821010c010b0b1045000b419b800841221000000b2000200a36020c200020093602082000200b370300200241106a24000b0f00200020012003200210144100470b060010af01000b0d002000103e2200100c1a20000b2e01017f41bd80084117102f220420002001100d1a200441d480084103100d1a200420022003100d1a2004100e000b3b01037f103d21022000280200210103404180d50828020020014a04402000200141016a22033602002002200110461049200321010c010b0b20020b4601017f230041106b220224002002200141187420014180fe03714108747220014108764180fe03712001411876727236020c20002002410c6a4104100d1a200241106a24000b2401017e4100101022014280808080105a04402000410a41808008410e1047000b2001a70b1f0020001046220010054120470440200120024182820841101047000b20000b190020004180d5082802004e04400f0b41e8800841121000000b1400101120004604400f0b41fa800841191000000b190020004180d5082802004c04400f0b41d7800841111000000b0b004180d50810113602000b7b02027f017e230041406a22012400200141086a200041046a1051200129030821032001200036021c200120033702140340200141206a200141146a102c200129032050450440200128023c20012903302001280238200128022810041a102e220010382000105220001036200010300c010b0b200141406b24000b2e01017f230041106b220224002002200128020010672000200228020436020420002001360200200241106a24000b7701017f230041106b220224002002200042388620004280fe0383422886842000428080fc0783421886200042808080f80f834208868484200042088842808080f80f832000421888428080fc07838420004228884280fe038320004238888484843703082001200241086a41081026200241106a24000b5001017f230041106b220224002002410036020c20002002410c6a410420011023200228020c2100200241106a2400200041187420004180fe03714108747220004108764180fe0371200041187672720b3801027f2000280200210310012104200028020820032001200410124504402000200120036a36020020040f0b200241938108410f1024000b09002000200110021a0b0a0020002000200110070b1b002000420053044041a2810841111000000b41722000100641720b0d002000416710181a416710050b080020012000105a0b4601017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a4104100d1a200241106a24000b080020002001105c0b09002000200110191a0b3b01017f102e210220012802002002105e2001280204200210382001280208200210382002200128020c105520012d00102002102520002002105c0b080020002001107f0b4d01017f102e210220012802002002105e200220012802041055200128020820021038200128020c2002103620012802102002103820012802142002103820012d00182002102520002002105c0b0a0020004101410010610b0d00200020012002102f10191a0b1200416c4101410010151a2000416c10191a0b0a0020002001106410620b190020001027220041b381084107100d1a20002001105520000bef0101037f230041206b22042400200020012802002206200128020822002002102d200020021064102e2100200328020820001038200329030020001052200328020c200010362000105c200620021066450440200441106a2001280204220310672004200428021c41016a220036021c02402004280210220545044020042000360214410021010c010b200441086a200320042802182201102a200320012004280208200010680b2003200020014100106820042000360218200341d281084106200010692002105b2004200541016a3602102003200441106a106a20062002106b2000ad106c0b200441206a24000b0b0020002001106f4100470bab0101057f230041206b22022400024002402001107e220110584504400c010b2002410c6a22032001103120032001105321062002410c6a2001105321032002410c6a2001105321042002410c6a2001105321052002280210200228020c470d0120022d001c450d0041f8d408410036020041fcd40841003a00000b2000200536020c200020043602082000200336020420002006360200200241206a24000f0b200141808008410e1024000b2000200041c78108410b200110692002102e2200107f20032000107f2000105c0b170020001027220020012002100d1a20032000105a20000b4601017f2000107e21022001280200220004402000102e2200107f20012802042000107f20012802082000107f200128020c2000107f20022000105c0f0b20024101410010610b190020001027220041ba81084108100d1a20002001105520000b890101047f230041106b22022400200220013c000f20022001421888a722033a000c20022001421088a722043a000d20022001420888a722053a000e200241003602082000200320047241ff017145220041044105200341ff01711b6a41002000200541ff01711b22006a200041002001501b6a2200200241086a6a410820006b1061200241106a24000bec0102027f017e230041206b22032400200341046a2204200120021064220110312004200110342102200342003703182004200341186a4108200110232003290318210520042001103321042003280208200328020446044020032d0014044041f8d408410036020041fcd40841003a00000b2000200436020c200020023602082000200542388620054280fe0383422886842005428080fc0783421886200542808080f80f834208868484200542088842808080f80f832005421888428080fc07838420054228884280fe03832005423888848484370300200341206a24000f0b200141808008410e1024000b0a0020002001106b10600b2a01017e20002001106b22002000107022024280808080105a0440200041808008410e1024000b2002a70ba30102017e027f230041106b22032400200342003703082000103222041005220041094f0440200141808008410e1024000b20044100200320006b41106a200010441a20032903082102200341106a2400200242388620024280fe0383422886842002428080fc0783421886200242808080f80f834208868484200242088842808080f80f832002421888428080fc07838420024228884280fe038320024238888484840b090020002001ad106c0b270002402002450d002001107b2002490d002000200210732003105d0f0b41c4860841121000000b190020001027220041c281084105100d1a20002001105920000ba70101057f230041206b220324002003410c6a220420012002107322011031200420011053210220042001103421052003410c6a200110342106200420011075210720042001102221042003280210200328020c46044020032d001c044041f8d408410036020041fcd40841003a00000b200020043a00102000200736020c200020063602082000200536020420002002360200200341206a24000f0b200141808008410e1024000b0a0020004120200110540b0a0020002001107310770b1f01017f2000103222011005412047044020004182820841101024000b20010bc80101077f230041206b220324002003410c6a22042001200210732201103120042001105321022004200110752105200420011034210620042001103321072003410c6a2001103421082003410c6a20011034210920042001102221042003280210200328020c46044020032d001c044041f8d408410036020041fcd40841003a00000b200020043a001820002009360214200020083602102000200736020c200020063602082000200536020420002002360200200341206a24000f0b200141808008410e1024000b250002402003450d002002107b2003490d0020002001200310780f0b41c4860841121000000b250002402003450d002002107b2003490d0020002001200310740f0b41c4860841121000000b2401017e20002000107022014280808080105a0440200041808008410e1024000b2001a70b1000200041c78108410b2001106910600b1000200041d2810841062001106910600b130020001027220041d881084105100d1a20000b4501017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a41041026200241106a24000b08002000103210350b4201037f20002802082203200110820145044020002802042202107b21042000280200200441016a220010732001105b200220001071200320012002107b1083010b0b0c00200020011085014100470b0e00200020011084012002ad106c0b190020001027220041dd81084106100d1a20002001105520000b0b0020002001108401107b0b2501027f2001102721022001102721032000200136020420002003360200200020023602080b7d01037f230041106b22012400200028020821032001410036020c200028020020034102742001410c6a41041044450440200128020c21022000200341016a360208200241187420024180fe03714108747220024108764180fe0371200241187672721027200141106a24000f0b41928208410841d7800841111047000b5601017e024020002001280208200128020449047e200110870110890122024280808080105a0d0120002001108701108901370310200020023e020842010542000b3703000f0b41928208410841808008410e1047000ba30102017e027f230041106b220224002002420037030820001005220341094f044041928208410841808008410e1047000b20004100200220036b41106a200310441a20022903082101200241106a2400200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc07838420014228884280fe038320014238888484840b14001041108b01450440419a820841251039000b0b2601017f230041106b22012400200141046a108c01200128020c2000108201200141106a24000b3601037f418d83084118102f22011027210220011027220341fe81084104100d1a2000200336020420002001360200200020023602080b0a0041c682084109102f0b1901017f41cf8208410c102f220220011059200020021086010b1901017f41db82084110102f220220011059200020021086010b0a0041eb82084112102f0b0b00200041fd820810b0010b0b0020004185830810b0010b6701027f230041106b2201240002402000450d00200141086a109101200128020c107b2000490d002001109101200128020021022001280204107b20004f04402002200010731058450d01200141106a24000f0b41c4860841121000000b41bb840841161039000b6701027f230041106b2201240002402000450d00200141086a109201200128020c107b2000490d002001109201200128020021022001280204107b20004f04402002200010731058450d01200141106a24000f0b41c4860841121000000b41d1840841161039000b3e01017f230041206b2201240020011092012001410c6a200128020020012802042000107a20012d001c45044041f9840841161039000b200141206a24000b4001017f230041306b22012400200141086a109101200141146a2001280208200128020c2000107920012d002c044041af8508410e1039000b200141306a24000bb70101057f230041206b22002400101a104f4100104e20004100360214200041146a2203104821042000280214104c104121012003108c01200320011081012004100521012000410036021020002001410276220136020c2000200436020802400340200120024b0440200041086a1087011027220210054120470d02200041146a2201108c0120012002108101200028020c2101200028021021020c010b0b200041206a24000f0b4192820841084182820841101047000b0800101a4100104d0b6101027f101a108a014102104d4100104621004101103e2201100f02402000101b04402001103b41ff01714101470d01109001200010191a108d012200105845044020002001103710191a0b0f0b41ff850841161039000b41958608410b1039000b810101047f230041306b22002400101a108a014101104d41a58308104a22011093012001109601200041086a109101200041146a22022000280208200028020c20011079200041013a002c200010910102402001450d0020002802002000280204107b2001490d00200110732002105f200041306a24000f0b41c4860841121000000ba10101057f230041306b22002400101a108a014101104d41a58308104a22011093012001109601200041086a109101200041106a22022000280208200028020c200110792000280214109001103221042000108d0110800136021c20004200370310200020043602182002103a200010910102402001450d0020002802002000280204107b2001490d00200110731062200041306a24000f0b41c4860841121000000b8d0101037f230041306b22002400101a108a014101104d41af8308104a2201109401200041106a1092012000411c6a200028021020002802142001107a20002d002c044041bd850841121039000b200041086a1092012000411c6a22022000280208200028020c2001107a200041013a002c200010920120002802002000280204200120021072200041306a24000b6901037f230041306b22002400101a108a014101104d41af8308104a22011094012001109501200041106a1092012000411c6a2202200028021020002802142001107a200041003a002c200041086a1092012000280208200028020c200120021072200041306a24000be70201087f23004180016b22002400101a108a014102104d41a58308104a2101410141cf85084104104b21022001109301200041d8006a22062001108e01200041186a200028025820002802602002102d200029031850450440200041386a200041286a2903003703002000200041206a2903003703302002200041306a103a200041f4006a2001108e01200028027422072002106f22050440200041106a200028027822012005102a2000280214210320002802102104200620011067024020040440200041086a20012004102a200120042000280208200310680c010b2000200336025c0b024020030440200020012003102a200120032004200028020410680c010b200020043602600b20012005107c20012005102b1a20012005107d2000200028025841016b3602582001200041d8006a106a20072002106e200041e0006a200028027c22012002106d2001200210630b20004180016a24000f0b41e6850841191039000bda0602097f027e230041d0016b22002400101a108a01104f4101104e41a58308104a2105200041013602a001200041a0016a1048210220002802a001104c2005109301103d21042002100521060340200141046a220320064b450440200041003602a00120022001200041a0016a410410441a200420002802a001220141187420014180fe03714108747220014108764180fe03712001411876727210271049200321010c010b0b200410052101200041003602702000200141027636026c2000200436026803400240200041a0016a200041e8006a10880120002903a00150044020094291ce005a0d01200041d0006a2005108e01200041c8006a109201200028024c21042000280248210620021005210120004100360264200020014102763602602000200236025c200041d4006a210203400240200041e8006a200041dc006a108801200029036850044020004180016a2005108e01200041286a20004184016a22011051200020002903283702a0010340200041206a200041a0016a102920002802200440200028028801200028022410630c0105200041186a20011051200020002903183702a0010340200041106a200041a0016a1029200028021004402000280280012000280214106e0c0105200041e8006a2000280284011067200028026c210103402001450d06200041086a2000280284012001102a200028020c2000280284012001107c2000280284012001107d21010c000b000b000b000b000b000b2000290378210920004180016a2006200420002802702207107a2000280280012005470d01103d2103200041406b2002105120002000290340370294012000200041d0006a36029c010340200041a0016a220120004194016a102c20002903a001500440200041386a10920120012000280238200028023c2007107a20002802ac01200041306a103c20032000280230200028023410400c030520002802b801210820002903b001210a20002802bc012201200120091057101c200120014290ce001057101d200020013602cc012000200a3703c001200020083602c8012003200041c0016a103f0c010b000b000b0b200041a8016a4200370300200042003703a001200028028401200041a0016a106a200041d0016a24000f0520002903b00120097c21090c020b000b0b418f850841201039000bdc0101077f230041406a220024004102104d410010462101410110462102200041106a104302401090011032200028021810280440108d01108001200028021c101e0d0110412103200041086a109101200028020c107b2104103d2105103e220642001006200041003a003c2000200236023820002001360234200020063602302000200536022c200020033602282000200441016a3602242000109101200028020020002802042201107b41016a22021073200041246a105f20012002ad106c200041406b24000f0b41ee8308412a1039000b4198840841231039000b850102057f017e230041206b22002400101a4103104d41a58308104a210141011046210241021046210310412104200041003a001c2000200436021820002003360214200020023602102000200136020c2000109201200028020020002802042201107b41016a220210732000410c6a105d20012002ad2205106c2005101f200041206a24000bc10101067f230041f0006b220024004101104d41a58308104a22011093012000109101200041d0006a2203200028020020002802042001107920002d00680440200041086a22041043104121022000411c6a2001108e01200041286a200028021c20002802242002102d02402000290328500440200041c4006a22052001108e01200320052002200410650c010b200028023c20002802141056200041d0006a2000411c6a2002200041306a10650b200041f0006a24000f0b41e7840841121039000bbe0101047f230041d0006b220024004101104d41af8308104a220110940120011095012000104310412102200041146a2001108f01024002402000280214220320021066450440200041206a22032001108f01200041386a20032002200010650c010b200041206a2003200028021c2002102d2000290320500d0020002802342000280230200028020810271028450d01200028020c1056200041386a200041146a2002200041286a10650b200041d0006a24000f0b41bf8308412f1039000b1000101a4100104d109001103210041a0b1000101a4100104d108d0110800110200bac01010b7f230041306b22002400101a4100104d200041086a10910120002802082103200028020c107b21044101210203400240200220044b0d00200041146a20032002107820002d002c22054102460d00200028022820002802242000280220200028021c2000280218210a102e210120002802142001105e2001200a10021a2001103820011036200110382001103820052001102520011030200241016a21020c010b0b200041306a24000b970101097f230041206b22002400101a4100104d2000109201200028020021032000280204107b21044101210203400240200220044b0d002000410c6a20032002107420002d001c22054102460d002000280218210620002802142000280210102e2101200028020c2001105e20011038200110382001200610021a20052001102520011030200241016a21020c010b0b200041206a24000b2e01027f230041106b22002400101a4101104d200041046a220141a58308104a108e0120011050200041106a24000b2e01027f230041106b22002400101a4101104d200041046a220141af8308104a108f0120011050200041106a24000b1800101a4101104d410041bf82084107104b108b01ad10210b3901037f230041106b22002400101a10424101104d410041bf82084107104b2101200041046a2202108c0120022001108101200041106a24000bd00101087f230041106b22012400101a10424101104d410041bf82084107104b2104200141046a108c010240200128020c22052004108501220204400240200220012802082203107b22004d044020002002460d012003107b2000490d03200128020422072000107621062003107b2002490d032007200210732006105b0c010b0c020b2003107b20004904400c020b20012802042000107310622003200041016b1071200020024704402005200620021083010b2005200410840110620b200141106a24000f0b41c4860841121000000b5401047f230041106b22002400101a4100104d200041046a108c012000280208107b210220002802042103410121010340200120024b45044020032001107610041a200141016a21010c010b0b200041106a24000b02000b0b0041d68608410e1000000b2701027f20014108102f22021027220341fe81084104100d1a20002003360204200020023602000b0bf8060200418080080be406696e70757420746f6f206c6f6e67696e76616c69642076616c7565696e636f7272656374206e756d626572206f662045534454207472616e7366657273617267756d656e74206465636f6465206572726f722028293a20746f6f2066657720617267756d656e7473746f6f206d616e7920617267756d656e747377726f6e67206e756d626572206f6620617267756d656e7473696e70757420746f6f2073686f72746361737420746f20693634206572726f722e6d61707065642e6e6f64655f69642e6974656d2e6e6f64655f6c696e6b732e76616c75652e696e666f2e696e64657873746f72616765206465636f6465206572726f7220286b65793a202e6c656e626164206172726179206c656e6774687661722061726773456e64706f696e742063616e206f6e6c792062652063616c6c65642062792061646d696e7361646472657373666565416d6f756e74706f74446f6e6174696f6e7370726f6a656374446f6e6174696f6e73666565546f6b656e4964656e746966696572706f746c6f636b7370726f6a656374736f6e6c795f61646d696e5f6d6f64756c653a61646d696e73706f746c6f636b5f696470726f6a6563745f696461646d696e73416c7265616479206d6164652061207061796d656e742077697468206120646966666572656e7420546f6b656e494457726f6e6720746f6b656e206964656e74696669657220666f72206372656174696e67206120706f742157726f6e672066656520616d6f756e7420666f72206372656174696e67206120706f74506f746c6f636b20646f65736e27742065786973742150726f6a65637420646f65736e277420657869737421506f74206973206e6f74206163746976652150726f6a656374206973206e6f742061637469766521546f74616c2070657263656e7461676573206d6f7265207468616e2031303025506f74206973206163746976652150726f6a65637420697320616374697665217573657270726f6a6563745f70657263656e74616765734e6f20646f6e6174696f6e20666f7220746869732075736572496e76616c696420746f6b656e2070726f7669646564416d6f756e742069732030456e64706f696e742063616e206f6e6c792062652063616c6c6564206279206f776e6572696e646578206f7574206f662072616e676570616e6963206f636375727265640041e486080b0438ffffff", + "report": { + "imports": [ + "bigIntAdd", + "bigIntCmp", + "bigIntFinishUnsigned", + "bigIntGetUnsignedArgument", + "bigIntMul", + "bigIntSetInt64", + "bigIntSign", + "bigIntTDiv", + "checkNoPayment", + "getNumArguments", + "mBufferAppend", + "mBufferAppendBytes", + "mBufferCopyByteSlice", + "mBufferEq", + "mBufferFinish", + "mBufferFromBigIntUnsigned", + "mBufferGetArgument", + "mBufferGetByteSlice", + "mBufferGetLength", + "mBufferNew", + "mBufferSetBytes", + "mBufferStorageLoad", + "mBufferStorageStore", + "mBufferToBigIntUnsigned", + "managedCaller", + "managedGetMultiESDTCallValue", + "managedMultiTransferESDTNFTExecute", + "managedOwnerAddress", + "managedSignalError", + "signalError", + "smallIntFinishSigned", + "smallIntFinishUnsigned", + "smallIntGetUnsignedArgument", + "validateTokenIdentifier" + ], + "isMemGrow": false, + "eiCheck": { + "eiVersion": "1.3", + "ok": true + }, + "codeReport": { + "path": "../output/potlock.wasm", + "size": 12628, + "hasAllocator": false, + "hasPanic": "without message" + } + } +} diff --git a/contracts/potlock/output/potlock.wasm b/contracts/potlock/output/potlock.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e3e11c45ff3ff9d7e26c18997a84f4bad4000429 GIT binary patch literal 12628 zcmbW7YmgjQd4|vFp4pw<-j$B+#a>Gy^o(V+GL|fivJ%3W?X@LiEXxWKmlzXiv@?=s zFEgu|S=j=km2KHT5-#Qv2#`cTh)IAzRet13ASo&#RVi>NlTd+Fr7BdQDyhUj@`I!Z zVTm#4Rfp=6F7wc^ktL>V+?Y;+_^)@8i^-d@BY|49J$x{|Z&3t`zait!H zT)oD1);_VaRBv{Jh`o-WhS@XSddHNs+|@bJLj#)hd|V%dVzJjXrRI9APtj|7V`quA z(Zc0MBqF{3M7?`pWvMr<6AUtuvv@~q`Hc8DwAh%dn-NVI&6Ue)!3fu^iF3)&^?475 z7!c6zp`UsnxNh!beQx1E z>tOYa*R_=x*PX5|Hfq&w{cvlc-n_ep5gNxE*w+JVBnXKG16XpQ58v519UAfhcPuT3 zHLmR`I>56p(U{hn2-Gg=@&=r^c%BSgubHv3`nK&+sSWjYCWIrB?e4G;z_c`H&r6Sw7LO z*6QZN*3F%)Hc!;|)$99O?Srju$Nah-sm{&Sm%BWfkJynmlTX+6@KJkJ=)n)bUA5b2 zHOMB(Vu2?B%@BNy&XWV8#e5SO`7;b*>Oerl+M@B7~-D6Bz z$V~SACuntdZb*&V9BZY+^OcfDv&y~WcC47t2iGnwq{FFABX{R`!4E5!#%w}ciFMLa zSdi(WIbV)bTV`11?t?8>N(&2Fe5zvS%R{N9DJ~adI?^KCiJ4+XSCNr+zEVhs?jAQu zk`A$sU8sy^51*=x%$E!3$)@pq#X<@iBbnLH(mZu5Q8sz141XG0%nC5Tn$dzzHRpLoW3m+X;&c?g$`MM0 zxhRDR%hW;|=Q75UG49D|y^Lr#EkSpE;y#b@-Ch6?XYYTcl&u#4Znkzc`xl-zx?3u7 zYFxB|?q|S9?8dqE2GNaMXOe9U9>5xQ`>{QhnY#oz4Cf)|UM!;krz9~fEqjh{NY*pc z*@_Jd*u2lhnR!j}CL8BeV?b!9qCzDqtinZUUQeb{-~ySOAcm60rlUfdH@&1BWww}^ zqzvUWQV$e@7CjH=Y;ccsp(5gOHYV%a?5~j+HM&N{x|gCs>keT?b^BXXIu$v;+CE`v zo7q&D5oR-)$Rk{!l5PuOQPvju6v5Za!w9L_Iw{zph3p$F2P|E~J(&EBjiS})EPC9L z`z#$>lj2upy0-VVH7- z4arOCq3za6uGfDuu9>%2jGH8`B%@w9x6}Q6vQD>J;1GX@ z*T!Af8|QY>u{*%=b`QsEH>5VX@8Tc|^hc@S*hFRwshJ*aW{Fojc1P` zc?4v#0-%R+_c|Uu>_!3?Amr_&eTrwS4FnaTvF8{O^c8X)3~e!6S#~PTyW0eSF@h97 zrSgz_rGgx{ZcBL>aqX;efQbJEH>|)ljRm8$v@3S}3{OXsxT_d&uR;g0Vv(DX#RSUa z8j}&(-8B_-c$XCU>W#^@vdJsUV*QnCzSA>RupFi`$@L7(zWYQ;e;%U?6(6fi@(rQc z%SQ(CF6LQQxa_iYUwa6cYmXkUJ+bJOapj?78tU;qyZec>FbmbkW~ZJwuiJA!9DZze z(zl*F_k;D1&6b`xua43?=u-ptle%Y|+NZc@I(NI@asK@IT|Q*Qne)*uSZ}?z-mE++ zcBKsjYY$!HMo`5Idk>>%Ept2E@E2VVk9sN?@H5m&3TTS@hT6vcf}FIZpp_CGHt`ehiY7c@ zQ?eNu#@(zT=|Po}`2KBr+M&DMx=fJ`+;+s-jaaYcZ<@ay!UL0M7BIH#c#(23iaUWt zz+;|>efH0l_~0eOjaSNpPDx}Fyx z3sfJ`T6vczqG&_Nl32?PCmVsqtT{x0`2=-|H*nTQ)k9g^r_AgGiIq!{>=q|`SlOb>aYTgWPKfe_@6eExRd||JceduWh)@wDiURz7pR6F$ckcE zKA?(@o7eg>lpA@&1KP5<3j5ri&4FAoir4vU8Hopq+@NQF15>n+V%!7XWu^7%8ixJ^43!2k^iFFF z7stNa*mVJO!qZcgc#i?xJUAW-d(60hDDhC-W7eTWjOpc13vE@Ndx2>oD`H+AHqK{A zg<*AHF^cBMcW@(EVrFTc*p`|FSLMN{+<))aeEn?|J6kqU=&RP>Q0>%)N@d9;prK?I z6@@-vJ*ka24=*E>dAM^akc_m^n)nGDEgwXKAVr1p;#w%@win8EyB5le1EIV)5Xy`F zP!6dO%7MpaAd!3cf;*brl<#*abp?avN~EQF$+^GfOQWZfPuhqh^W0#*E|x0f*th!g z6O)bT;9_8-i0{Avik4p+m2haPBqe&Sr;#LP!CvjFwe#B7v(c}8qXCJd0g0o&#E_E2 zc@&o8ZZXkJ8sS7(<*jMN$pL_fT!*6Q&6EgVp}zHXgGvM+3Wuq%I2@ZVeEH7}-2UP@7RutWT+RWwOC3`W*V5#>rRU9wwg(_7D?p96)X34<5Z1S1rQR}NFB~O$P z3Mz7hPoIF^lIRqfPbncuP3|#@&@pJy^*E9Gu5i*|-Fdp@KYhRWCnOl^`GsJwMh^UJ`YkbtG@=pNFZuR;j0wIxiwsB*j^zeV0FYxKo0VSH_^J z9_3~oC;a5yx7)&e#d3`KJ~j-cER_0e8(xn|qZx6gWTn(~H%B|xz1_NZ+J3+rw;B-| zb^ZYBw@0P^u}`0D00Lw$iiiHBx)%?1(xO*-W7W?tg4#Y!c%P{Udb9-k2kn-`6T~X$KMcBwbf>v&HFUNi_?gKIGcG&3r zs`V-dA&+twlHxR0%ii@^DVt=A*|#yW{Rl)90wVJ2!*5Y?V~?8buUKk?6Ec6u@^v1@ zpdf@0Rsr7=HuQX(9(QRE)Blb3tC=pKW&itV$$cRluV#-w=I>AR&$i${!m>Wflh)mn zK@6gRQ53LwgAqKjyV{kb)I6 z_Mr6e_HZKRBdT0Oe8cWrv{Tq5JN|cX8iRakIuoXI_8QEY>p{n#J;akt+!;~083Lbw zTnD+x2Z0?raQMTuL}xY|x53><<#s@5^+6dz6y&cCF=fK-cNvh41sN5$k7&!5pK^xa zZL{cf1w<%=sYs1x;u!^_%Ox_{J3)D_sS+O zVseM-9|)9S7FO>~svrWsf0?D-y|nBrv)$1FqgyY0xQz-a;e;}?6xi;)&}Xyb-eswV zRkp*cb-T3x!P9??hCBkY4^k#1($yn*v5J<1j#$gG)~A5vYgp&~u z<&~W9`9-vUwa2GdWlCHHf@d+XyvSoHWPgO%*-h*fa+_)G~}O!h6KmuJ?!TMxV(f$AG| zISOI6&w3x?ftl^r{$*;O&9hDk`HwsJhaHM!h$?es|HU>Z5Sxm+6^_$gt5WnXr|Nqu zdZ=PKKEFw~6H3%_FJ2om=LBHX;i_arfd&6w3U~;+u{)_9Es1zKdLUt79DIe2n;6TM zS>p=5QNZUYafO8*_Scv2E`o=*iEG5m?7}ocT9!h3_!65Tw5jM}c#PZ<10pxa zs^~K~!M~!s>xGGb9EwK5yQZfHR87RP?m({WBJ%+C1+8+y&J(%36I`%vKdijpat^A~ z7!IKom-GsgHw*U!RTJ@;N45xaF_;dX#o7gX#ZzCmW#HU&ASf;)y@KL&w8$MQIvLNP zNzWbE@1u!#u;AACf<1_KM`oY=nz?^mEIf@`iUA;BWmLf5{t$^@ty6`y$Xn|#a+EvD zt_PU^jF~S-`C=?X%Xj*Vozz-h!@VV@G~hf3E|!B&47N3%+J)R`Nr>YjZElq^QcazT z#Pw9P+0BhvDP1r4dNX+im(LXX)@Hge^PHbK;hJHl=WQyYq~z#xDq8e!fr*bpOa+rP zQI_g#hr6-<+Oa!M9TR)_3w9A;;jv zuzo64qT44QQsllPn(^sFNK0TDf(`h5t2Q>;%^O|^lP&RCHZ45q zP@SatAC#>(Nv7<>luI}0?r|Fx`|mA%jOK%YfdDNTk$GP^Mg{;QHuXN)XGG7DHmER7 zauCztFn7qyaWyvY-t4)m6ydArUIam3t^I|yL&_A-8lNdHEh1DKFckO^mHHBceX56T z=A?Jo5=T?+4!D#}$f9`)k^5o=T{Z*hZ4o|-3kNs<3IvN`WSnx^NR+Spz%JA>W5T^Y zEE`CQGWe|vSpM@T6Xr zAz15f14vJs9dG(2~0p?~&bb*Y%r*i($rN_jVz{D*= zg3HTB4`jWs?>G2*$fe0=txaU4Uge-76N-IQYyaxk1l*a;Lo7PIM;xl~mW&Vif`(6P zqJ4pJ5G~ViNpYH*W%i5=sxyN8|b z=Uh2?dH=Y<({ZyGkCL{L$5ZG9ov?G1-=4b z$($eX zwWt3y^SeWh=JHB6?Y3I!Vyk(g(exj?rd(I*jpkgd-R6tPw7If$tlmyr$5VZzoObhX zpgYz4qvW(!pKI0XX+W#M=4*_!1@; z>Sy+(+ZXH2W7Qf=wX0`R9{4i+bhRxeJA0e8L)d&I zccCX+Y}c!`GpH8zSJUP2;d1(5qkEFaT0l~%VLM#6Gh^&hNWX3W9BeOhbPJIyWKwEhs^)0Pj0?^G{sZFSQ|CvEamo$EGE z*ZboxZav)URu|LddV3D8F1cq;ffoFP z4}ZNN-IEZ}*t>JU2bD1MG-{~@TWX;lS3p5apY?l`r7ipj55YH1)R(Kx#$4K(n_Izw OYDOP7C57F5o%4UVqbZC4 literal 0 HcmV?d00001 diff --git a/contracts/potlock/sc-config.toml b/contracts/potlock/sc-config.toml new file mode 100644 index 0000000..15d4cf8 --- /dev/null +++ b/contracts/potlock/sc-config.toml @@ -0,0 +1,4 @@ + +[[proxy]] +path = "interact-rs/src/proxy.rs" + diff --git a/contracts/potlock/src/potlock.rs b/contracts/potlock/src/potlock.rs new file mode 100644 index 0000000..6d0502d --- /dev/null +++ b/contracts/potlock/src/potlock.rs @@ -0,0 +1,29 @@ +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); +pub mod potlock_admin_interactions; +pub mod potlock_interactions; +pub mod potlock_requirements; +pub mod potlock_storage; + +#[multiversx_sc::contract] +pub trait Potlock: + potlock_admin_interactions::PotlockAdminInteractions + + potlock_interactions::PotlockInteractions + + potlock_requirements::PotlockRequirements + + potlock_storage::PotlockStorage + + multiversx_sc_modules::only_admin::OnlyAdminModule +{ + #[init] + fn init(&self, admins: MultiValueEncoded) { + let caller = self.blockchain().get_caller(); + self.admins().insert(caller); + for admin in admins { + self.admins().insert(admin); + } + } + + #[upgrade] + fn upgrade(&self) {} +} diff --git a/contracts/potlock/src/potlock_admin_interactions.rs b/contracts/potlock/src/potlock_admin_interactions.rs new file mode 100644 index 0000000..bf38a93 --- /dev/null +++ b/contracts/potlock/src/potlock_admin_interactions.rs @@ -0,0 +1,132 @@ +use crate::{ + potlock_requirements::{self, MAX_PERCENTAGE}, + potlock_storage::{self, PotlockId, ProjectId, Status}, +}; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub type ProjectPercentage = MultiValue2; + +#[multiversx_sc::module] +pub trait PotlockAdminInteractions: + potlock_requirements::PotlockRequirements + + potlock_storage::PotlockStorage + + multiversx_sc_modules::only_admin::OnlyAdminModule +{ + #[only_admin] + #[endpoint(changeFeeForPots)] + fn change_fee_for_pots(&self, token_identifier: TokenIdentifier, fee: BigUint) { + require!( + token_identifier.is_valid_esdt_identifier(), + "Invalid token provided" + ); + require!(fee > 0, "Amount is 0"); + self.fee_token_identifier().set_if_empty(&token_identifier); + self.fee_amount().set_if_empty(fee); + } + + #[only_admin] + #[endpoint(acceptPot)] + fn accept_pot(&self, potlock_id: PotlockId) { + self.require_potlock_exists(potlock_id); + self.require_potlock_is_inactive(potlock_id); + + let mut accepted_potlock = self.potlocks().get(potlock_id); + accepted_potlock.status = Status::Active; + self.potlocks().set(potlock_id, &accepted_potlock); + } + + #[only_admin] + #[endpoint(removePot)] + fn remove_pot(&self, potlock_id: PotlockId) { + self.require_potlock_exists(potlock_id); + self.require_potlock_is_inactive(potlock_id); + + let potlock_mapper = self.potlocks(); + let pot_proposer = potlock_mapper.get(potlock_id).proposer; + let fee_pot_payment = EsdtTokenPayment::new( + self.fee_token_identifier().get(), + 0u64, + self.fee_amount().get(), + ); + + self.send() + .direct_non_zero_esdt_payment(&pot_proposer, &fee_pot_payment); + self.potlocks().clear_entry(potlock_id); + } + + #[only_admin] + #[endpoint(acceptApplication)] + fn accept_application(&self, project_id: ProjectId) { + self.require_project_exists(project_id); + self.require_project_is_inactive(project_id); + + let mut accepted_project = self.projects().get(project_id); + accepted_project.status = Status::Active; + self.projects().set(project_id, &accepted_project); + } + + #[only_admin] + #[endpoint(removeApplication)] + fn remove_application(&self, project_id: ProjectId) { + self.require_project_exists(project_id); + self.require_project_is_active(project_id); + + let mut rejected_project = self.projects().get(project_id); + rejected_project.status = Status::Inactive; + self.projects().set(project_id, &rejected_project); + } + + #[only_admin] + #[endpoint(rejectDonation)] + fn reject_donation(&self, potlock_id: PotlockId, user: ManagedAddress) { + self.require_potlock_exists(potlock_id); + let opt_fee_pot_payment = self.pot_donations(potlock_id).get(&user); + + require!(opt_fee_pot_payment.is_some(), "No donation for this user"); + let fee_pot_payment = unsafe { opt_fee_pot_payment.unwrap_unchecked() }; + + self.send() + .direct_non_zero_esdt_payment(&user, &fee_pot_payment); + self.pot_donations(potlock_id).remove(&user); + } + + #[only_admin] + #[endpoint(distributePotToProjects)] + fn distribute_pot_to_projects( + &self, + potlock_id: PotlockId, + project_percentages: MultiValueEncoded, + ) { + self.require_potlock_exists(potlock_id); + self.require_correct_percentages(project_percentages.clone()); + let pot_donations = self.pot_donations(potlock_id); + let all_projects = self.projects(); + + for pp in project_percentages { + let (project_id, percentage) = pp.into_tuple(); + let project = all_projects.get(project_id); + + // The project must previously apply to this Pot + if project.potlock_id != potlock_id { + continue; + } + + let mut output_payments = ManagedVec::new(); + for (_, donation) in pot_donations.iter() { + let project_share_amount = donation.amount * percentage / MAX_PERCENTAGE; + let project_share = EsdtTokenPayment::new( + donation.token_identifier, + donation.token_nonce, + project_share_amount, + ); + output_payments.push(project_share); + } + let project_owner = self.projects().get(project_id).owner; + self.send().direct_multi(&project_owner, &output_payments); + } + + self.pot_donations(potlock_id).clear(); + } +} diff --git a/contracts/potlock/src/potlock_interactions.rs b/contracts/potlock/src/potlock_interactions.rs new file mode 100644 index 0000000..15ebbd0 --- /dev/null +++ b/contracts/potlock/src/potlock_interactions.rs @@ -0,0 +1,106 @@ +use crate::potlock_requirements; +use crate::potlock_storage::{self, Pot, Project}; +use crate::potlock_storage::{PotlockId, ProjectId}; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[multiversx_sc::module] +pub trait PotlockInteractions: + potlock_requirements::PotlockRequirements + + potlock_storage::PotlockStorage + + multiversx_sc_modules::only_admin::OnlyAdminModule +{ + #[payable("*")] + #[endpoint(addPot)] + fn add_pot(&self, name: ManagedBuffer, description: ManagedBuffer) { + let payment_for_adding_pot = self.call_value().single_esdt(); + require!( + self.fee_token_identifier().get() == payment_for_adding_pot.token_identifier, + "Wrong token identifier for creating a pot!" + ); + require!( + self.fee_amount().get() == payment_for_adding_pot.amount, + "Wrong fee amount for creating a pot" + ); + let caller = self.blockchain().get_caller(); + + let potlock_id = self.potlocks().len() + 1; + let potlock = Pot::new(potlock_id, caller, name, description); + self.potlocks().push(&potlock); + } + + #[endpoint(applyForPot)] + fn apply_for_pot( + &self, + potlock_id: PotlockId, + project_name: ManagedBuffer, + description: ManagedBuffer, + ) -> usize { + let owner = self.blockchain().get_caller(); + let project = Project::new(potlock_id, project_name, description, owner); + self.projects().push(&project) + } + + #[payable("*")] + #[endpoint(donateToPot)] + fn donate_to_pot(&self, potlock_id: PotlockId) { + self.require_potlock_exists(potlock_id); + self.require_potlock_is_active(potlock_id); + + let payment = self.call_value().single_esdt(); + let caller = self.blockchain().get_caller(); + let mut donation_mapper = self.pot_donations(potlock_id); + + if donation_mapper.contains_key(&caller) { + let opt_payment = donation_mapper.get(&caller); + if opt_payment.is_some() { + let mut previous_payment = opt_payment.unwrap(); + require!( + previous_payment.token_identifier == payment.token_identifier.clone(), + "Already made a payment with a different TokenID" + ); + previous_payment.amount += payment.amount; + donation_mapper.insert(caller, previous_payment); + } + } else { + donation_mapper.insert(caller, payment); + } + + // match donation_mapper.get(&caller) { + // Some(mut previous_payment) => { + // // let a = pot_donations.get(&caller).unwrap(); + // previous_payment.amount += payment.amount; + // pot_donations.insert(caller, previous_payment); + // } + // None => { + // self.pot_donations(potlock_id).insert(caller, payment); + // } + // } + } + + #[payable("*")] + #[endpoint(donateToProject)] + fn donate_to_project(&self, project_id: ProjectId) { + self.require_project_exists(project_id); + self.require_project_is_active(project_id); + let payment = self.call_value().single_esdt(); + let caller = self.blockchain().get_caller(); + + let mut donation_mapper = self.project_donations(project_id); + if donation_mapper.contains_key(&caller) { + let opt_payment = donation_mapper.get(&caller); + if opt_payment.is_some() { + let mut previous_payment = opt_payment.unwrap(); + require!( + previous_payment.token_identifier == payment.token_identifier.clone(), + "Already made a payment with a different TokenID" + ); + previous_payment.amount += payment.amount; + donation_mapper.insert(caller, previous_payment); + } + } else { + donation_mapper.insert(caller, payment); + } + } +} diff --git a/contracts/potlock/src/potlock_requirements.rs b/contracts/potlock/src/potlock_requirements.rs new file mode 100644 index 0000000..f923672 --- /dev/null +++ b/contracts/potlock/src/potlock_requirements.rs @@ -0,0 +1,69 @@ +use crate::{ + potlock_admin_interactions::ProjectPercentage, + potlock_storage::{self, PotlockId, ProjectId, Status}, +}; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub const MAX_PERCENTAGE: u64 = 10_000; // 100% + +#[multiversx_sc::module] +pub trait PotlockRequirements: potlock_storage::PotlockStorage { + fn is_valid_potlock_id(&self, potlock_id: PotlockId) -> bool { + potlock_id >= 1 && potlock_id <= self.potlocks().len() + } + + fn require_potlock_exists(&self, potlock_id: PotlockId) { + require!( + self.is_valid_potlock_id(potlock_id) && !self.potlocks().item_is_empty(potlock_id), + "Potlock doesn't exist!", + ) + } + + fn require_potlock_is_active(&self, potlock_id: PotlockId) { + let potlock = self.potlocks().get(potlock_id); + require!(potlock.status == Status::Active, "Pot is not active!",) + } + + fn require_potlock_is_inactive(&self, potlock_id: PotlockId) { + let potlock = self.potlocks().get(potlock_id); + require!(potlock.status != Status::Active, "Pot is active!",) + } + + fn is_valid_project_id(&self, project_id: ProjectId) -> bool { + project_id >= 1 && project_id <= self.projects().len() + } + + fn require_project_exists(&self, project_id: ProjectId) { + require!( + self.is_valid_project_id(project_id) && !self.projects().item_is_empty(project_id), + "Project doesn't exist!", + ) + } + + fn require_project_is_active(&self, project_id: ProjectId) { + let project = self.projects().get(project_id); + require!(project.status == Status::Active, "Project is not active!",) + } + + fn require_project_is_inactive(&self, project_id: ProjectId) { + let project = self.projects().get(project_id); + require!(project.status != Status::Active, "Project is active!",) + } + + fn require_correct_percentages( + &self, + project_percentages: MultiValueEncoded, + ) { + let mut total_perc: u64 = 0; + for pp in project_percentages { + let (_, perc) = pp.into_tuple(); + total_perc += perc; + } + require!( + total_perc <= MAX_PERCENTAGE, + "Total percentages more than 100%" + ); + } +} diff --git a/contracts/potlock/src/potlock_storage.rs b/contracts/potlock/src/potlock_storage.rs new file mode 100644 index 0000000..19b71bd --- /dev/null +++ b/contracts/potlock/src/potlock_storage.rs @@ -0,0 +1,103 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub type PotlockId = usize; +pub type ProjectId = usize; + +#[derive(TypeAbi, TopEncode, TopDecode, PartialEq, Eq, Debug, NestedEncode, NestedDecode)] +pub enum Status { + Inactive, + Active, +} + +#[derive(TypeAbi, NestedEncode, NestedDecode, PartialEq, Debug, TopEncode, TopDecode)] +pub struct Pot { + pub potlock_id: PotlockId, + pub proposer: ManagedAddress, + pub token_identifier: TokenIdentifier, + pub fee: BigUint, + pub name: ManagedBuffer, + pub description: ManagedBuffer, + pub status: Status, +} + +impl Pot { + pub fn new( + potlock_id: PotlockId, + proposer: ManagedAddress, + name: ManagedBuffer, + description: ManagedBuffer, + ) -> Self { + Pot { + potlock_id, + proposer, + token_identifier: TokenIdentifier::from(ManagedBuffer::default()), + fee: BigUint::default(), + name, + description, + status: Status::Inactive, + } + } +} + +#[derive(TypeAbi, NestedEncode, NestedDecode, PartialEq, Debug, TopEncode, TopDecode)] +pub struct Project { + pub potlock_id: PotlockId, + pub name: ManagedBuffer, + pub description: ManagedBuffer, + pub owner: ManagedAddress, + pub status: Status, +} + +impl Project { + pub fn new( + potlock_id: PotlockId, + name: ManagedBuffer, + description: ManagedBuffer, + owner: ManagedAddress, + ) -> Self { + Project { + potlock_id, + name, + description, + owner, + status: Status::Inactive, + } + } +} + +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, PartialEq, Debug)] +pub struct UserDonations { + pub user: ManagedAddress, + pub donations: EsdtTokenPayment, +} + +#[multiversx_sc::module] +pub trait PotlockStorage { + #[view(getFeeTokenIdentifier)] + #[storage_mapper("feeTokenIdentifier")] + fn fee_token_identifier(&self) -> SingleValueMapper; + + #[view(getFeeAmount)] + #[storage_mapper("feeAmount")] + fn fee_amount(&self) -> SingleValueMapper; + + #[view(getPotlocks)] + #[storage_mapper("potlocks")] + fn potlocks(&self) -> VecMapper>; + + #[view(getProjects)] + #[storage_mapper("projects")] + fn projects(&self) -> VecMapper>; + + #[view(potDonations)] + #[storage_mapper("potDonations")] + fn pot_donations(&self, potlock_id: PotlockId) -> MapMapper; + + #[view(projectDonations)] + #[storage_mapper("projectDonations")] + fn project_donations( + &self, + project_id: ProjectId, + ) -> MapMapper; +} diff --git a/contracts/potlock/tests/potlock_blackbox_tests.rs b/contracts/potlock/tests/potlock_blackbox_tests.rs new file mode 100644 index 0000000..95ca710 --- /dev/null +++ b/contracts/potlock/tests/potlock_blackbox_tests.rs @@ -0,0 +1,979 @@ +use multiversx_sc_scenario::{imports::*, ScenarioWorld}; +use potlock::potlock_storage::{PotlockId, ProjectId}; +mod potlock_proxy; + +const POTLOCK_ADDRESS: TestSCAddress = TestSCAddress::new("potlock"); +const POTLOCK_CODE_PATH: MxscPath = MxscPath::new("output/potlock.mxsc.json"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const ADMIN_ADDRESS: TestAddress = TestAddress::new("admin"); +const POT_PROPOSER_ADDRESS: TestAddress = TestAddress::new("pot_proposer"); +const PROJECT_PROPOSER_ADDRESS: TestAddress = TestAddress::new("project_proposer"); +const POT_DONOR_ADDRESS: TestAddress = TestAddress::new("pot_donor"); +const PROJECT_DONOR_ADDRESS: TestAddress = TestAddress::new("project_donor"); +const POT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("POT-123456"); +const DIFFERENT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("DIFFPOT-123456"); +const POT_FEE_CREATION: u64 = 1_000; +const DIFFERENT_POT_FEE_CREATION: u64 = 2_000; +const INITIAL_BALANCE: u64 = 2_000; +const DONATION_AMOUNT: u64 = 100; +const HALF_PERCENTAGE: u64 = 5_000; // 50% +const MAX_PERCENTAGE: u64 = 10_000; // 100% + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract(POTLOCK_CODE_PATH, potlock::ContractBuilder); + blockchain +} + +struct PotlockTestState { + world: ScenarioWorld, +} + +impl PotlockTestState { + fn new() -> Self { + let mut world = world(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .account(ADMIN_ADDRESS) + .nonce(1) + .account(POT_PROPOSER_ADDRESS) + .nonce(1) + .esdt_balance(POT_TOKEN_ID, INITIAL_BALANCE) + .esdt_balance(DIFFERENT_TOKEN_ID, INITIAL_BALANCE) + .account(PROJECT_PROPOSER_ADDRESS) + .nonce(1) + .account(POT_DONOR_ADDRESS) + .nonce(1) + .esdt_balance(POT_TOKEN_ID, INITIAL_BALANCE) + .esdt_balance(DIFFERENT_TOKEN_ID, INITIAL_BALANCE) + .account(PROJECT_DONOR_ADDRESS) + .nonce(1) + .esdt_balance(POT_TOKEN_ID, INITIAL_BALANCE) + .esdt_balance(DIFFERENT_TOKEN_ID, INITIAL_BALANCE); + + Self { world } + } + + fn deploy_potlock_contract(&mut self) -> &mut Self { + let mut admins: MultiValueEncoded> = + MultiValueEncoded::new(); + admins.push(ADMIN_ADDRESS.to_managed_address()); + + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .init(admins) + .code(POTLOCK_CODE_PATH) + .new_address(POTLOCK_ADDRESS) + .run(); + self + } + + fn change_fee_for_pots(&mut self, fee_amount: u64) { + self.world + .tx() + .from(ADMIN_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .change_fee_for_pots( + TokenIdentifier::from(POT_TOKEN_ID), + BigUint::from(fee_amount), + ) + .run(); + } + + fn add_pot(&mut self, name: &str, description: &str) { + self.world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .add_pot(name, description) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(POT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(POT_FEE_CREATION), + ) + .run(); + } + + fn accept_pot(&mut self, potlock_id: PotlockId) { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .accept_pot(potlock_id) + .run(); + } + + fn accept_application(&mut self, project_id: ProjectId) { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .accept_application(project_id) + .run(); + } + + fn remove_pot(&mut self, potlock_id: PotlockId) { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .remove_pot(potlock_id) + .run(); + } + + fn apply_for_pot( + &mut self, + potlock_id: PotlockId, + project_name: &str, + description: &str, + ) -> usize { + let new_project_id = self + .world + .tx() + .from(PROJECT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .apply_for_pot(potlock_id, project_name, description) + .returns(ReturnsResult) + .run(); + + new_project_id + } + + fn donate_to_pot(&mut self, potlock_id: PotlockId, donation_token: TestTokenIdentifier) { + self.world + .tx() + .from(POT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_pot(potlock_id) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(donation_token), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DONATION_AMOUNT), + ) + .run(); + } + + fn donate_to_project(&mut self, project_id: ProjectId) { + self.world + .tx() + .from(PROJECT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_project(project_id) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(POT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DONATION_AMOUNT), + ) + .run(); + } + + fn distribute_pot_to_projects( + &mut self, + potlock_id: PotlockId, + percentages: MultiValueVec>, + ) { + self.world + .tx() + .from(ADMIN_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .distribute_pot_to_projects(potlock_id, percentages) + .run(); + } + + ////////// Checks ////////// + fn check_esdt_balance(&mut self, address: TestAddress, balance: u64) { + self.world + .check_account(address) + .esdt_balance(POT_TOKEN_ID, balance); + } + + fn check_sc_esdt_balance(&mut self, address: TestSCAddress, balance: u64) { + self.world + .check_account(address) + .esdt_balance(POT_TOKEN_ID, balance); + } + + fn check_potlock_id_is_last(&mut self, potlock_id: PotlockId) { + let potlocks = self + .world + .query() + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .potlocks() + .returns(ReturnsResult) + .run(); + assert_eq!(potlocks.len(), potlock_id); + } + + fn check_project_id_is_last(&mut self, project_id: PotlockId) { + let projects = self + .world + .query() + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .projects() + .returns(ReturnsResult) + .run(); + assert_eq!(projects.len(), project_id); + } + + fn check_project_is_accepted(&mut self, project_description: ManagedBuffer) { + let projects = self + .world + .query() + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .projects() + .returns(ReturnsResult) + .run(); + + let mut project_found = false; + for project in projects.into_iter() { + if project.description == project_description { + project_found = true; + } + } + assert!(project_found); + } +} + +#[test] +fn test_deploy_and_config() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); +} + +#[test] +fn test_change_fee_for_pots_twice() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.change_fee_for_pots(POT_FEE_CREATION * 2); + + state.add_pot("Pot", "Pot description"); + + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); +} + +#[test] +fn test_add_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); +} + +#[test] +fn test_accept_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + state.accept_pot(potlock_id); + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); +} + +#[test] +fn test_remove_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + + state.remove_pot(potlock_id); + + // Funds were returned to user + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, 0); +} + +#[test] +fn test_apply_for_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_potlock_id_is_last(potlock_id); + state.check_project_id_is_last(new_project_id); + + // Funds were returned to user + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); +} + +#[test] +fn test_donate_to_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE); + + state.donate_to_pot(potlock_id, POT_TOKEN_ID); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); +} + +#[test] +fn test_donate_to_pot_twice(){ + let mut state = PotlockTestState::new(); + + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE); + + state.donate_to_pot(potlock_id, POT_TOKEN_ID); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); + + state.donate_to_pot(potlock_id, POT_TOKEN_ID); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + 2 * DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - 2 * DONATION_AMOUNT); + +} + +#[test] +fn test_donate_to_project() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + state.check_project_id_is_last(new_project_id); + + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(PROJECT_DONOR_ADDRESS, INITIAL_BALANCE); + + state.donate_to_project(new_project_id); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(PROJECT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); +} + +#[test] +fn test_accept_application() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id: usize = 1usize; + state.check_potlock_id_is_last(potlock_id); + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_project_id_is_last(new_project_id); + state.check_esdt_balance(POT_PROPOSER_ADDRESS, POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); +} + +#[test] +fn test_distribute_pot_to_projects() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + // Add Pot + state.add_pot("Pot", "Pot Description"); + let potlock_id: usize = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + // Add Project + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_project_id_is_last(new_project_id); + state.check_esdt_balance(POT_PROPOSER_ADDRESS, POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + + // Donate to Pot + state.donate_to_pot(potlock_id, POT_TOKEN_ID); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); + + // Accept project + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + // Distribute Pot donations to projects + let mut percentages = MultiValueVec::new(); + percentages.push((new_project_id, MAX_PERCENTAGE).into()); + state.distribute_pot_to_projects(potlock_id, percentages); + + state.check_esdt_balance(PROJECT_PROPOSER_ADDRESS, DONATION_AMOUNT); +} + +#[test] +fn test_distribute_to_project_less_than_max_percent() +{ + let mut state = PotlockTestState::new(); + + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + // Add Pot + state.add_pot("Pot", "Pot Description"); + let potlock_id: usize = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + // Add Project + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_project_id_is_last(new_project_id); + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + + // Donate to Pot + state.donate_to_pot(potlock_id, POT_TOKEN_ID); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); + + // Accept project + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + // Distribute Pot donations to projects + let mut percentages = MultiValueVec::new(); + percentages.push((new_project_id, 60).into()); + state.distribute_pot_to_projects(potlock_id, percentages); + + state.check_esdt_balance(PROJECT_PROPOSER_ADDRESS, DONATION_AMOUNT * (60/100)); + //state.check_sc_esdt_balance(POTLOCK_ADDRESS, 0); +} + + +///////////// Negative tests ////////////// + +#[test] +fn test_fail_add_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .add_pot("name", "description") + .with_result(ExpectError(4, "incorrect number of ESDT transfers")) + .run(); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, 0); +} + +#[test] +fn test_fail_add_pot_wrong_payment() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .add_pot("name", "description") + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(DIFFERENT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(POT_FEE_CREATION), + ) + .with_result(ExpectError(4, "Wrong token identifier for creating a pot!")) + .run(); + + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .add_pot("name", "description") + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(POT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DIFFERENT_POT_FEE_CREATION), + ) + .with_result(ExpectError(4, "Wrong fee amount for creating a pot")) + .run(); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, 0); +} + +#[test] +fn test_fail_change_fee_for_pots() +{ + let mut state = PotlockTestState::new(); + + state.deploy_potlock_contract(); + + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .change_fee_for_pots( + TokenIdentifier::from(POT_TOKEN_ID), + BigUint::from(0u64), + ) + .returns(ExpectError(4, "Endpoint can only be called by admins")) + .run(); +} + +#[test] +fn test_fail_accept_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + + let potlock_id = 1usize; + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .accept_pot(potlock_id) + .with_result(ExpectError(4, "Endpoint can only be called by admins")) + .run(); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); +} + +#[test] +fn test_fail_accept_pot_non_existent() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + let potlock_id = 0usize; + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .accept_pot(potlock_id) + .with_result(ExpectError(4, "Potlock doesn't exist!")) + .run(); +} + +#[test] +fn test_fail_remove_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + + let potlock_id = 1usize; + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .remove_pot(potlock_id) + .with_result(ExpectError(4, "Endpoint can only be called by admins")) + .run(); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); +} + +#[test] +fn test_fail_remove_pot_non_existent() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + let potlock_id = 0usize; + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .remove_pot(potlock_id) + .with_result(ExpectError(4, "Potlock doesn't exist!")) + .run(); +} + +#[test] +fn test_fail_accept_application() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_potlock_id_is_last(potlock_id); + state.check_project_id_is_last(new_project_id); + + // Funds were returned to user + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .accept_application(new_project_id) + .with_result(ExpectError(4, "Endpoint can only be called by admins")) + .run(); +} + +#[test] +fn test_fail_distribute_pot_to_projects() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id: usize = 1usize; + state.check_potlock_id_is_last(potlock_id); + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_project_id_is_last(new_project_id); + state.check_esdt_balance(POT_PROPOSER_ADDRESS, POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + let mut percentages = MultiValueVec::new(); + percentages.push((new_project_id, HALF_PERCENTAGE).into()); + state + .world + .tx() + .from(POT_PROPOSER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .distribute_pot_to_projects(potlock_id, percentages) + .with_result(ExpectError(4, "Endpoint can only be called by admins")) + .run(); +} + +#[test] +fn test_fail_distribute_pot_to_projects2() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + // Add Pot + state.add_pot("Pot", "Pot Description"); + let potlock_id: usize = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + // Add Project + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + + state.check_project_id_is_last(new_project_id); + state.check_esdt_balance(POT_PROPOSER_ADDRESS, POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + + // Donate to Pot + state.donate_to_pot(potlock_id, POT_TOKEN_ID); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); + + // Accept project + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + // Distribute Pot donations to projects + let mut percentages = MultiValueVec::new(); + percentages.push((new_project_id, 3 * HALF_PERCENTAGE).into()); + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .distribute_pot_to_projects(potlock_id, percentages) + .with_result(ExpectError(4, "Total percentages more than 100%")) + .run(); +} + +#[test] +fn test_fail_donate_to_project() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + state.check_project_id_is_last(new_project_id); + + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(PROJECT_DONOR_ADDRESS, INITIAL_BALANCE); + + state.donate_to_project(new_project_id); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(PROJECT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); + + state + .world + .tx() + .from(PROJECT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_project(new_project_id) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(DIFFERENT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DONATION_AMOUNT), + ) + .with_result(ExpectError( + 4, + "Already made a payment with a different TokenID", + )) + .run(); +} + +#[test] +fn test_fail_donate_to_inactive_project() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + state.check_project_id_is_last(new_project_id); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(PROJECT_DONOR_ADDRESS, INITIAL_BALANCE); + + state + .world + .tx() + .from(PROJECT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_project(new_project_id) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(DIFFERENT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DONATION_AMOUNT), + ) + .with_result(ExpectError( + 4, + "Project is not active!", + )) + .run(); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(PROJECT_DONOR_ADDRESS, INITIAL_BALANCE); +} + +#[test] +fn test_fail_donate_to_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + // Accept Pot + state.accept_pot(potlock_id); + + let new_project_id = state.apply_for_pot(potlock_id, "Project name", "Project description"); + state.check_project_id_is_last(new_project_id); + + state.accept_application(new_project_id); + state.check_project_is_accepted(ManagedBuffer::from("Project description")); + + state.check_esdt_balance(POT_PROPOSER_ADDRESS, INITIAL_BALANCE - POT_FEE_CREATION); + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE); + + state.donate_to_pot(new_project_id, POT_TOKEN_ID); + + state.check_sc_esdt_balance(POTLOCK_ADDRESS, POT_FEE_CREATION + DONATION_AMOUNT); + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE - DONATION_AMOUNT); + + state + .world + .tx() + .from(POT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_pot(new_project_id) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(DIFFERENT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DONATION_AMOUNT), + ) + .with_result(ExpectError( + 4, + "Already made a payment with a different TokenID", + )) + .run(); +} + +#[test] +fn test_fail_donate_to_non_active_pot() { + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + state.add_pot("Pot", "Pot Description"); + let potlock_id = 1usize; + state.check_potlock_id_is_last(potlock_id); + + state + .world + .tx() + .from(PROJECT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_pot(potlock_id) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(DIFFERENT_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(DONATION_AMOUNT), + ) + .with_result(ExpectError( + 4, + "Pot is not active!", + )) + .run(); +} + +#[test] +fn test_fail_donate_to_non_existing_pot(){ + let mut state = PotlockTestState::new(); + state.deploy_potlock_contract(); + state.change_fee_for_pots(POT_FEE_CREATION); + + let potlock_id = 0usize; + state + .world + .tx() + .from(POT_DONOR_ADDRESS) + .to(POTLOCK_ADDRESS) + .typed(potlock_proxy::PotlockProxy) + .donate_to_pot(potlock_id) + .with_result(ExpectError(4, "Potlock doesn't exist!")) + .run(); + + state.check_esdt_balance(POT_DONOR_ADDRESS, INITIAL_BALANCE); +} diff --git a/contracts/potlock/tests/potlock_proxy.rs b/contracts/potlock/tests/potlock_proxy.rs new file mode 100644 index 0000000..687a658 --- /dev/null +++ b/contracts/potlock/tests/potlock_proxy.rs @@ -0,0 +1,390 @@ +// Code generated by the multiversx-sc proxy generator. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +#![allow(dead_code)] +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct PotlockProxy; + +impl TxProxyTrait for PotlockProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PotlockProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PotlockProxyMethods { wrapped_tx: tx } + } +} + +pub struct PotlockProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PotlockProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + admins: Arg0, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&admins) + .original_result() + } +} + +#[rustfmt::skip] +impl PotlockProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl PotlockProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn change_fee_for_pots< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_identifier: Arg0, + fee: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeFeeForPots") + .argument(&token_identifier) + .argument(&fee) + .original_result() + } + + pub fn accept_pot< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("acceptPot") + .argument(&potlock_id) + .original_result() + } + + pub fn remove_pot< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removePot") + .argument(&potlock_id) + .original_result() + } + + pub fn accept_application< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("acceptApplication") + .argument(&project_id) + .original_result() + } + + pub fn remove_application< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeApplication") + .argument(&project_id) + .original_result() + } + + pub fn reject_donation< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + potlock_id: Arg0, + user: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("rejectDonation") + .argument(&potlock_id) + .argument(&user) + .original_result() + } + + pub fn distribute_pot_to_projects< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + potlock_id: Arg0, + project_percentages: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributePotToProjects") + .argument(&potlock_id) + .argument(&project_percentages) + .original_result() + } + + pub fn add_pot< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + name: Arg0, + description: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addPot") + .argument(&name) + .argument(&description) + .original_result() + } + + pub fn apply_for_pot< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + potlock_id: Arg0, + project_name: Arg1, + description: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("applyForPot") + .argument(&potlock_id) + .argument(&project_name) + .argument(&description) + .original_result() + } + + pub fn donate_to_pot< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("donateToPot") + .argument(&potlock_id) + .original_result() + } + + pub fn donate_to_project< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("donateToProject") + .argument(&project_id) + .original_result() + } + + pub fn fee_token_identifier( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeTokenIdentifier") + .original_result() + } + + pub fn fee_amount( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeAmount") + .original_result() + } + + pub fn potlocks( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPotlocks") + .original_result() + } + + pub fn projects( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getProjects") + .original_result() + } + + pub fn pot_donations< + Arg0: ProxyArg, + >( + self, + potlock_id: Arg0, + ) -> TxTypedCall, EsdtTokenPayment>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("potDonations") + .argument(&potlock_id) + .original_result() + } + + pub fn project_donations< + Arg0: ProxyArg, + >( + self, + project_id: Arg0, + ) -> TxTypedCall, EsdtTokenPayment>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("projectDonations") + .argument(&project_id) + .original_result() + } + + pub fn is_admin< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isAdmin") + .argument(&address) + .original_result() + } + + pub fn add_admin< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addAdmin") + .argument(&address) + .original_result() + } + + pub fn remove_admin< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeAdmin") + .argument(&address) + .original_result() + } + + pub fn admins( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAdmins") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub struct Pot +where + Api: ManagedTypeApi, +{ + pub potlock_id: usize, + pub proposer: ManagedAddress, + pub token_identifier: TokenIdentifier, + pub fee: BigUint, + pub name: ManagedBuffer, + pub description: ManagedBuffer, + pub status: Status, +} + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedDecode, NestedEncode)] +pub enum Status { + Inactive, + Active, +} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub struct Project +where + Api: ManagedTypeApi, +{ + pub potlock_id: usize, + pub name: ManagedBuffer, + pub description: ManagedBuffer, + pub owner: ManagedAddress, + pub status: Status, +} diff --git a/contracts/potlock/wasm/Cargo.lock b/contracts/potlock/wasm/Cargo.lock new file mode 100644 index 0000000..4732b4c --- /dev/null +++ b/contracts/potlock/wasm/Cargo.lock @@ -0,0 +1,198 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "multiversx-sc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "potlock" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "potlock-wasm" +version = "0.0.0" +dependencies = [ + "multiversx-sc-wasm-adapter", + "potlock", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" diff --git a/contracts/potlock/wasm/Cargo.toml b/contracts/potlock/wasm/Cargo.toml new file mode 100644 index 0000000..0ead938 --- /dev/null +++ b/contracts/potlock/wasm/Cargo.toml @@ -0,0 +1,34 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "potlock-wasm" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" +overflow-checks = false + +[profile.dev] +panic = "abort" + +[dependencies.potlock] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.52.3" + +[workspace] +members = ["."] diff --git a/contracts/potlock/wasm/src/lib.rs b/contracts/potlock/wasm/src/lib.rs new file mode 100644 index 0000000..8bb6ebd --- /dev/null +++ b/contracts/potlock/wasm/src/lib.rs @@ -0,0 +1,47 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Upgrade: 1 +// Endpoints: 21 +// Async Callback (empty): 1 +// Total number of exported functions: 24 + +#![no_std] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + potlock + ( + init => init + upgrade => upgrade + changeFeeForPots => change_fee_for_pots + acceptPot => accept_pot + removePot => remove_pot + acceptApplication => accept_application + removeApplication => remove_application + rejectDonation => reject_donation + distributePotToProjects => distribute_pot_to_projects + addPot => add_pot + applyForPot => apply_for_pot + donateToPot => donate_to_pot + donateToProject => donate_to_project + getFeeTokenIdentifier => fee_token_identifier + getFeeAmount => fee_amount + getPotlocks => potlocks + getProjects => projects + potDonations => pot_donations + projectDonations => project_donations + isAdmin => is_admin + addAdmin => add_admin + removeAdmin => remove_admin + getAdmins => admins + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {} From bc78006eca9c9bac92c3dfc0d6052c5d2b56d535 Mon Sep 17 00:00:00 2001 From: sergiuosvat Date: Thu, 22 Aug 2024 12:05:29 +0300 Subject: [PATCH 2/3] fixed lottery-esdt tests --- .../scenarios/wrong-start-params.scen.json | 376 ------------------ .../tests/lottery_esdt_blackbox.rs | 74 ++-- .../tests/lottery_esdt_scenario_rs_test.rs | 5 - 3 files changed, 51 insertions(+), 404 deletions(-) delete mode 100644 contracts/lottery-esdt/scenarios/wrong-start-params.scen.json diff --git a/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json b/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json deleted file mode 100644 index 1864db6..0000000 --- a/contracts/lottery-esdt/scenarios/wrong-start-params.scen.json +++ /dev/null @@ -1,376 +0,0 @@ -{ - "steps": [ - { - "step": "setState", - "accounts": { - "address:OWNER_ADDRESS": { - "nonce": "1" - } - } - }, - { - "step": "setState", - "accounts": { - "address:FIRST_ADDRESS": { - "nonce": "1", - "esdt": { - "str:BSK-476470": "1000" - } - } - } - }, - { - "step": "setState", - "accounts": { - "address:SECOND_ADDRESS": { - "nonce": "1", - "esdt": { - "str:BSK-476470": "1000" - } - } - } - }, - { - "step": "setState", - "accounts": { - "address:THIRD_ADDRESS": { - "nonce": "1", - "esdt": { - "str:BSK-476470": "1000", - "str:TEST-123456": "1000" - } - } - } - }, - { - "step": "setState", - "currentBlockInfo": { - "blockTimestamp": "10" - } - }, - { - "step": "setState", - "newAddresses": [ - { - "creatorAddress": "address:OWNER_ADDRESS", - "creatorNonce": "1", - "newAddress": "sc:lottery-esdt" - } - ] - }, - { - "step": "scDeploy", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "contractCode": "mxsc:../output/lottery-esdt.mxsc.json", - "arguments": [], - "gasLimit": "5,000,000" - }, - "expect": { - "out": [], - "status": "0" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x", - "0x42534b2d343736343730", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Name can't be empty!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Invalid token name provided!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Ticket price must be higher than 0!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000000", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Must have more than 0 tickets available!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000384", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Only 800 or less total tickets per lottery are allowed!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000002", - "0x010000000000000000", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Deadline can't be in the past!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000002", - "0x010000000005f5e100", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Deadline can't be later than 30 days from now!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000000", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Must have more than 0 max entries per user!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000023c3c", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x0a" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Prize distribution must add up to exactly 100(%)!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x45474c44", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x65" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:EGLD can't be burned!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x42534b2d343736343730", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x65" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:The contract can't burn the selected token!" - } - }, - { - "step": "scCall", - "id": "", - "tx": { - "from": "address:OWNER_ADDRESS", - "to": "sc:lottery-esdt", - "function": "start", - "arguments": [ - "0x74657374", - "0x544553542d313233343536", - "0x01", - "0x0100000002", - "0x010000000000000014", - "0x0100000001", - "0x01000000024b19", - "0x010000000246495253545f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5345434f4e445f414444524553535f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", - "0x65" - ], - "gasLimit": "5,000,000" - }, - "expect": { - "status": "4", - "message": "str:Invalid burn percentage!" - } - } - ] -} diff --git a/contracts/lottery-esdt/tests/lottery_esdt_blackbox.rs b/contracts/lottery-esdt/tests/lottery_esdt_blackbox.rs index 268adda..6071c57 100644 --- a/contracts/lottery-esdt/tests/lottery_esdt_blackbox.rs +++ b/contracts/lottery-esdt/tests/lottery_esdt_blackbox.rs @@ -26,8 +26,6 @@ impl LotteryESDTTestState{ fn new() -> Self { let mut world = world(); - world.start_trace(); - world.account(OWNER_ADDRESS).nonce(1); world @@ -65,10 +63,6 @@ impl LotteryESDTTestState{ .run(); } - fn write_scenario_trace(&mut self, file_name: &str){ - self.world.write_scenario_trace(file_name); - } - fn start_lottery(&mut self) { let lottery_name = ManagedBuffer::new_from_bytes(&b"test"[..]); @@ -76,7 +70,7 @@ impl LotteryESDTTestState{ let ticket_price = BigUint::::from(1u128); let opt_total_tickets = Option::Some(2u32); let opt_deadline = Option::Some(20u64); - let opt_max_entries_per_user = Option::Some(1u32); + let opt_max_entries_per_user = Option::Some(2u32); let prize_distribution_data: &[u8] = &[75,25]; let opt_prize_distribution = Option::Some(ManagedVec::from_iter(prize_distribution_data.iter().copied())); let mut whitelist = ManagedVec::new(); @@ -143,6 +137,7 @@ impl LotteryESDTTestState{ fn start_lottery_error_params(&mut self, lottery_name_wrong: bool, token_identifier_wrong:u64, ticket_price_wrong:bool, opt_total_tickets_wrong: Option, opt_deadline_wrong: Option, opt_max_entries_per_user_wrong: bool, opt_prize_distribution_wrong: bool, opt_burn_percentage_wrong: bool, error: ExpectError) { + let token_id_burnable : &[u8] = &b"TEST-123456"[..]; let lottery_name = if lottery_name_wrong { ManagedBuffer::new_from_bytes(&b""[..]) } else { @@ -198,6 +193,8 @@ impl LotteryESDTTestState{ // .set_roles(TOKEN_BURNABLE) // .run(); + self.world.set_esdt_local_roles(SC_ADDRESS, token_id_burnable, &[EsdtLocalRole::Burn]); + self.world .tx() .from(OWNER_ADDRESS) @@ -267,6 +264,20 @@ impl LotteryESDTTestState{ .run(); } + fn determine_winner(&mut self) + { + let lottery_name = ManagedBuffer::new_from_bytes(&b"test"[..]); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(SC_ADDRESS) + .typed(proxy::LotteryProxy) + .determine_winner(&lottery_name) + .returns(ReturnsResult) + .run(); + } + fn determine_winner_error(&mut self, error: ExpectError) { let lottery_name = ManagedBuffer::new_from_bytes(&b"test"[..]); @@ -293,7 +304,6 @@ fn lottery_esdt_blackbox_init(){ world.deploy(); - world.write_scenario_trace("scenarios/init-lottery-esdt.scen.json"); } #[test] @@ -310,8 +320,24 @@ fn lottery_esdt_blackbox_buy_all() world.buy_ticket(SECOND_ADDRESS); world.buy_ticket_error(FIRST_ADDRESS, ExpectError(4,"Lottery entry period has ended! Awaiting winner announcement.")); +} + +#[test] +fn lottery_esdt_blackbox_buy_after_winner_announced() { + let mut world = LotteryESDTTestState::new(); + + world.deploy(); + + world.start_lottery(); - world.write_scenario_trace("scenarios/buy-all-tickets-and-exceed-max-tickets.scen.json"); + world.buy_ticket(FIRST_ADDRESS); + + world.buy_ticket(SECOND_ADDRESS); + + world.determine_winner(); + + world.buy_ticket_error(FIRST_ADDRESS, ExpectError(4,"Lottery is currently inactive.")); + } #[test] @@ -331,8 +357,6 @@ fn lottery_esdt_blackbox_buy_after_deadline() world.buy_ticket_error(FIRST_ADDRESS, ExpectError(4,"Lottery entry period has ended! Awaiting winner announcement.")); - world.write_scenario_trace("scenarios/buy-after-deadline.scen.json"); - } #[test] @@ -350,8 +374,6 @@ fn lottery_esdt_blackbox_buy_after_sold_out() world.buy_ticket_error(FIRST_ADDRESS, ExpectError(4,"Lottery entry period has ended! Awaiting winner announcement.")); - world.write_scenario_trace("scenarios/buy-after-sold-out.scen.json"); - } #[test] @@ -365,8 +387,6 @@ fn lottery_esdt_blackbox_buy_not_whitelisted() world.buy_ticket_error(THIRD_ADDRESS, ExpectError(4, "You are not allowed to participate in this lottery!")); - world.write_scenario_trace("scenarios/buy-not-whitelisted.scen.json"); - } #[test] @@ -379,8 +399,6 @@ fn lottery_esdt_blackbox_buy_wrong_fee() world.start_lottery(); world.buy_ticket_wrong_fee(FIRST_ADDRESS, BigUint::::from(2u128)); - - world.write_scenario_trace("scenarios/buy-wrong-fee.scen.json"); } @@ -397,8 +415,22 @@ fn lottery_esdt_blackbox_determine_winner_early() world.determine_winner_error(ExpectError(4,"Lottery is still running!")); - world.write_scenario_trace("scenarios/determine-winner-early.scen.json"); +} +#[test] +fn lottery_esdt_blackbox_determine_winner_one_participant() { + let mut world = LotteryESDTTestState::new(); + + world.deploy(); + + world.start_lottery(); + + world.buy_ticket(FIRST_ADDRESS); + + world.buy_ticket(FIRST_ADDRESS); + + world.determine_winner(); + } #[test] @@ -412,8 +444,6 @@ fn lottery_esdt_blackbox_start_lottery_twice() world.start_lottery_error(ExpectError(4,"Lottery is already active!")); - world.write_scenario_trace("scenarios/start-lottery-twice.scen.json"); - } #[test] @@ -452,8 +482,6 @@ fn lottery_esdt_blackbox_wrong_start_params() world.start_lottery_error_params(false, 0, false, total_tickets, deadline, false, false, true, ExpectError(4,"The contract can't burn the selected token!")); - //world.start_lottery_error_params(false, 3, false, total_tickets, deadline, false, false, true, ExpectError(4,"Invalid burn percentage!")); - - world.write_scenario_trace("scenarios/wrong-start-params.scen.json"); + world.start_lottery_error_params(false, 3, false, total_tickets, deadline, false, false, true, ExpectError(4,"Invalid burn percentage!")); } diff --git a/contracts/lottery-esdt/tests/lottery_esdt_scenario_rs_test.rs b/contracts/lottery-esdt/tests/lottery_esdt_scenario_rs_test.rs index 07e5a22..6f6d60e 100644 --- a/contracts/lottery-esdt/tests/lottery_esdt_scenario_rs_test.rs +++ b/contracts/lottery-esdt/tests/lottery_esdt_scenario_rs_test.rs @@ -199,8 +199,3 @@ fn start_with_all_options_rs() { fn start_with_no_options_rs() { world().run("scenarios/start-with-no-options.scen.json"); } - -#[test] -fn wrong_start_params_rs() { - world().run("scenarios/wrong-start-params.scen.json"); -} From 77ce73d33f12656c73f986ba18c05da352417f00 Mon Sep 17 00:00:00 2001 From: sergiuosvat Date: Thu, 22 Aug 2024 12:07:40 +0300 Subject: [PATCH 3/3] removed one go test --- .../lottery-esdt/tests/lottery_esdt_scenario_go_test.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/contracts/lottery-esdt/tests/lottery_esdt_scenario_go_test.rs b/contracts/lottery-esdt/tests/lottery_esdt_scenario_go_test.rs index c7c12b7..7d19c5e 100644 --- a/contracts/lottery-esdt/tests/lottery_esdt_scenario_go_test.rs +++ b/contracts/lottery-esdt/tests/lottery_esdt_scenario_go_test.rs @@ -188,8 +188,3 @@ fn start_with_all_options_go() { fn start_with_no_options_go() { world().run("scenarios/start-with-no-options.scen.json"); } - -#[test] -fn wrong_start_params_go() { - world().run("scenarios/wrong-start-params.scen.json"); -}