diff --git a/Cargo.lock b/Cargo.lock index e8b46e6b..3694dafe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1720,6 +1720,23 @@ dependencies = [ "memchr", ] +[[package]] +name = "on-chain-claim" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", +] + +[[package]] +name = "on-chain-claim-meta" +version = "0.0.0" +dependencies = [ + "multiversx-sc-meta", + "on-chain-claim", +] + [[package]] name = "once_cell" version = "1.19.0" diff --git a/Cargo.toml b/Cargo.toml index 57d808c6..c42e83ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,8 @@ members = [ "contracts/nft-minter/meta", "contracts/nft-storage-prepay", "contracts/nft-storage-prepay/meta", + "contracts/on-chain-claim", + "contracts/on-chain-claim/meta", "contracts/order-book/factory", "contracts/order-book/factory/meta", "contracts/order-book/pair", diff --git a/contracts/check-pause/wasm/src/lib.rs b/contracts/check-pause/wasm/src/lib.rs index 550768b6..b3f3bdda 100644 --- a/contracts/check-pause/wasm/src/lib.rs +++ b/contracts/check-pause/wasm/src/lib.rs @@ -10,7 +10,9 @@ // Total number of exported functions: 6 #![no_std] -#![allow(internal_features)] + +// Configuration that works with rustc < 1.73.0. +// TODO: Recommended rustc version: 1.73.0 or newer. #![feature(lang_items)] multiversx_sc_wasm_adapter::allocator!(); diff --git a/contracts/on-chain-claim/.gitignore b/contracts/on-chain-claim/.gitignore new file mode 100644 index 00000000..dd49a952 --- /dev/null +++ b/contracts/on-chain-claim/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ + +# Mandos test trace +trace*.scen.json diff --git a/contracts/on-chain-claim/Cargo.toml b/contracts/on-chain-claim/Cargo.toml new file mode 100644 index 00000000..675b4ba7 --- /dev/null +++ b/contracts/on-chain-claim/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "on-chain-claim" +version = "0.0.0" +authors = [ "Vlad Bucur "] +edition = "2021" +publish = false + +[lib] +path = "src/contract.rs" + +[dependencies.multiversx-sc] +version = "0.46.0" + +[dependencies.multiversx-sc-modules] +version = "0.46.0" + +[dev-dependencies.multiversx-sc-scenario] +version = "0.46.0" diff --git a/contracts/on-chain-claim/README.md b/contracts/on-chain-claim/README.md new file mode 100644 index 00000000..d4ccc0af --- /dev/null +++ b/contracts/on-chain-claim/README.md @@ -0,0 +1,3 @@ +# On Chain Claim + +`On Chain Claim` is a simple Smart Contract. diff --git a/contracts/on-chain-claim/interaction/devnet.snippets.sh b/contracts/on-chain-claim/interaction/devnet.snippets.sh new file mode 100644 index 00000000..d54534b5 --- /dev/null +++ b/contracts/on-chain-claim/interaction/devnet.snippets.sh @@ -0,0 +1,52 @@ +WALLET="${PWD}/wallet.pem" +PROJECT="${PWD}" +PROXY=https://devnet-gateway.multiversx.com +CHAINID=D + +DEPLOY_GAS="25000000" +SFT_IDENTIFIER=0x585354525245504149522d653162363733 #XSTRREPAIR-e1b673 + +CONTRACT_ADDRESS="erd1qqqqqqqqqqqqqpgqkm3wla3wk0yqk7lk725wee8yh0e2zeru76ls3gr0nj" + +deploy() { + mxpy --verbose contract deploy \ + --bytecode="output/on-chain-claim.wasm" \ + --arguments ${SFT_IDENTIFIER} \ + --pem=${WALLET} \ + --gas-limit=${DEPLOY_GAS} \ + --proxy=${PROXY} \ + --chain=${CHAINID} \ + --recall-nonce \ + --send \ + --outfile="deploy-devnet.interaction.json" || return + + TRANSACTION=$(mxpy data parse --file="deploy-devnet.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="deploy-devnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-devnet --value=${ADDRESS} + mxpy data store --key=deployTransaction-devnet --value=${TRANSACTION} + + echo "" + echo "Smart contract address: ${ADDRESS}" +} + +upgrade() { + mxpy --verbose contract upgrade ${CONTRACT_ADDRESS} \ + --bytecode="output/on-chain-claim.wasm" \ + --pem=${WALLET} \ + --gas-limit=${DEPLOY_GAS} \ + --proxy=${PROXY} \ + --chain=${CHAINID} \ + --recall-nonce \ + --send \ + --outfile="upgrade-devnet.interaction.json" || return + + TRANSACTION=$(mxpy data parse --file="upgrade-devnet.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="upgrade-devnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-devnet --value=${ADDRESS} + mxpy data store --key=upgradeTransaction-devnet --value=${TRANSACTION} + + echo "" + echo "Smart contract address: ${ADDRESS}" +} diff --git a/contracts/on-chain-claim/interaction/mainnet.snippets.sh b/contracts/on-chain-claim/interaction/mainnet.snippets.sh new file mode 100644 index 00000000..5a6b86a3 --- /dev/null +++ b/contracts/on-chain-claim/interaction/mainnet.snippets.sh @@ -0,0 +1,52 @@ +WALLET="${PWD}/wallet.pem" +PROJECT="${PWD}" +PROXY=https://gateway.multiversx.com +CHAINID=D + +DEPLOY_GAS="30000000" +SFT_IDENTIFIER=0x585354525245504149522d653162363733 #XSTRREPAIR-e1b673 + +CONTRACT_ADDRESS="erd1qqqqqqqqqqqqqpgqkm3wla3wk0yqk7lk725wee8yh0e2zeru76ls3gr0nj" + +deploy() { + mxpy --verbose contract deploy \ + --bytecode="output/on-chain-claim.wasm" \ + --arguments ${SFT_IDENTIFIER} \ + --pem=${WALLET} \ + --gas-limit=${DEPLOY_GAS} \ + --proxy=${PROXY} \ + --chain=${CHAINID} \ + --recall-nonce \ + --send \ + --outfile="deploy-mainnet.interaction.json" || return + + TRANSACTION=$(mxpy data parse --file="deploy-mainnet.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="deploy-mainnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-mainnet --value=${ADDRESS} + mxpy data store --key=deployTransaction-mainnet --value=${TRANSACTION} + + echo "" + echo "Smart contract address: ${ADDRESS}" +} + +upgrade() { + mxpy --verbose contract upgrade ${CONTRACT_ADDRESS} \ + --bytecode="output/on-chain-claim.wasm" \ + --pem=${WALLET} \ + --gas-limit=${DEPLOY_GAS} \ + --proxy=${PROXY} \ + --chain=${CHAINID} \ + --recall-nonce \ + --send \ + --outfile="upgrade-mainnet.interaction.json" || return + + TRANSACTION=$(mxpy data parse --file="upgrade-mainnet.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="upgrade-mainnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-mainnet --value=${ADDRESS} + mxpy data store --key=upgradeTransaction-mainnet --value=${TRANSACTION} + + echo "" + echo "Smart contract address: ${ADDRESS}" +} diff --git a/contracts/on-chain-claim/interaction/testnet.snippets.sh b/contracts/on-chain-claim/interaction/testnet.snippets.sh new file mode 100644 index 00000000..8342d994 --- /dev/null +++ b/contracts/on-chain-claim/interaction/testnet.snippets.sh @@ -0,0 +1,28 @@ +WALLET="${PWD}/wallet.pem" +PROJECT="${PWD}" +PROXY=https://testnet-gateway.multiversx.com +CHAINID=D + +DEPLOY_GAS="30000000" +SFT_IDENTIFIER=0x54525245504149522d626435323730 #XSTRREPAIR-e1b673 +deploy() { + mxpy --verbose contract deploy \ + --bytecode="output/on-chain-claim.wasm" \ + --arguments ${SFT_IDENTIFIER} \ + --pem=${WALLET} \ + --gas-limit=${DEPLOY_GAS} \ + --proxy=${PROXY} \ + --chain=${CHAINID} \ + --recall-nonce \ + --send \ + --outfile="deploy-testnet.interaction.json" || return + + TRANSACTION=$(mxpy data parse --file="deploy-testnet.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="deploy-testnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-testnet --value=${ADDRESS} + mxpy data store --key=deployTransaction-testnet --value=${TRANSACTION} + + echo "" + echo "Smart contract address: ${ADDRESS}" +} diff --git a/contracts/on-chain-claim/meta/Cargo.toml b/contracts/on-chain-claim/meta/Cargo.toml new file mode 100644 index 00000000..c7114aa0 --- /dev/null +++ b/contracts/on-chain-claim/meta/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "on-chain-claim-meta" +version = "0.0.0" +edition = "2018" +publish = false +authors = [ "Vlad Bucur "] + +[dev-dependencies] + +[dependencies.on-chain-claim] +path = ".." + +[dependencies.multiversx-sc-meta] +version = "0.46.0" +default-features = false diff --git a/contracts/on-chain-claim/meta/src/main.rs b/contracts/on-chain-claim/meta/src/main.rs new file mode 100644 index 00000000..6dc8f567 --- /dev/null +++ b/contracts/on-chain-claim/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/contracts/on-chain-claim/multiversx.json b/contracts/on-chain-claim/multiversx.json new file mode 100644 index 00000000..73655396 --- /dev/null +++ b/contracts/on-chain-claim/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/contracts/on-chain-claim/mxsc-template.toml b/contracts/on-chain-claim/mxsc-template.toml new file mode 100644 index 00000000..f08a40f4 --- /dev/null +++ b/contracts/on-chain-claim/mxsc-template.toml @@ -0,0 +1,19 @@ +name = "on-chain-claim" +contract_trait = "OnChainClaim" +src_file = "contract.rs" +rename_pairs = [ + [ + "blockchain.set_current_dir_from_workspace(\"contracts/examples/on-chain-claim\");", + "// blockchain.set_current_dir_from_workspace(\"relative path to your workspace, if applicable\");", + ], +] +files_include = [ + "meta", + "scenarios", + "src", + "tests", + "wasm/Cargo.toml", + "Cargo.toml", + "README.md", + "multiversx.json", +] diff --git a/contracts/on-chain-claim/src/address_info.rs b/contracts/on-chain-claim/src/address_info.rs new file mode 100644 index 00000000..9de9c8b5 --- /dev/null +++ b/contracts/on-chain-claim/src/address_info.rs @@ -0,0 +1,35 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(Default, NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +pub struct AddressInfo { + pub current_streak: u64, + pub last_epoch_claimed: u64, + pub total_epochs_claimed: u64, + pub best_streak: u64, +} + +impl AddressInfo { + pub fn new( + current_streak: u64, + last_epoch_claimed: u64, + total_epochs_claimed: u64, + best_streak: u64, + ) -> Self { + AddressInfo { + current_streak, + last_epoch_claimed, + total_epochs_claimed, + best_streak, + } + } + + pub fn new_with_epoch(current_epoch: u64) -> Self { + AddressInfo { + current_streak: 1, + last_epoch_claimed: current_epoch, + total_epochs_claimed: 1, + best_streak: 1, + } + } +} diff --git a/contracts/on-chain-claim/src/config.rs b/contracts/on-chain-claim/src/config.rs new file mode 100644 index 00000000..3d5d4c75 --- /dev/null +++ b/contracts/on-chain-claim/src/config.rs @@ -0,0 +1,58 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use crate::address_info::*; + +pub const SFT_AMOUNT: u64 = 1; +pub const MAX_REPAIR_GAP: u64 = 5; + +#[multiversx_sc::module] +pub trait ConfigModule { + fn require_same_shard(&self, address: &ManagedAddress) { + let address_shard = self.blockchain().get_shard_of_address(address); + let sc_address = self.blockchain().get_sc_address(); + let sc_shard = self.blockchain().get_shard_of_address(&sc_address); + + require!(address_shard == sc_shard, "wrong shard"); + } + + fn get_missed_epochs(&self, current_epoch: u64, last_epoch_claimed: u64) -> u64 { + if current_epoch <= last_epoch_claimed { + return 0; + } + + current_epoch - last_epoch_claimed - 1 + } + + #[view(getAddressInfo)] + fn get_address_info(&self, address: &ManagedAddress) -> AddressInfo { + let address_info_mapper = self.address_info(address); + + if address_info_mapper.is_empty() { + return AddressInfo::default(); + } + + address_info_mapper.get() + } + + #[view(canBeRepaired)] + fn can_be_repaired(&self, address: &ManagedAddress) -> bool { + let address_info_mapper = self.address_info(address); + if address_info_mapper.is_empty() { + return false; + } + + let address_info = address_info_mapper.get(); + let current_epoch = self.blockchain().get_block_epoch(); + let missed_epochs = self.get_missed_epochs(current_epoch, address_info.last_epoch_claimed); + + missed_epochs > 0 && missed_epochs <= MAX_REPAIR_GAP + } + + #[storage_mapper("address_info")] + fn address_info(&self, address: &ManagedAddress) -> SingleValueMapper; + + #[view(getRepairStreakTokenIdentifier)] + #[storage_mapper("repair_streak_token_identifier")] + fn repair_streak_token_identifier(&self) -> SingleValueMapper; +} diff --git a/contracts/on-chain-claim/src/contract.rs b/contracts/on-chain-claim/src/contract.rs new file mode 100644 index 00000000..bb4caea2 --- /dev/null +++ b/contracts/on-chain-claim/src/contract.rs @@ -0,0 +1,153 @@ +#![no_std] +#![allow(unused_attributes)] + +pub use address_info::AddressInfo; +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub mod address_info; +pub mod config; + +use crate::config::{MAX_REPAIR_GAP, SFT_AMOUNT}; +use multiversx_sc_modules::only_admin; + +#[multiversx_sc::contract] +pub trait OnChainClaimContract: config::ConfigModule + only_admin::OnlyAdminModule { + #[init] + fn init(&self, repair_streak_token_id: TokenIdentifier) { + self.internal_set_repair_streak_token_id(repair_streak_token_id); + + let caller = self.blockchain().get_caller(); + self.add_admin(caller); + } + + #[upgrade] + fn upgrade(&self) {} + + #[endpoint(claim)] + fn claim(&self) { + let caller = self.blockchain().get_caller(); + require!( + !self.blockchain().is_smart_contract(&caller), + "Only user accounts can perform claim" + ); + self.require_same_shard(&caller); + + let current_epoch = self.blockchain().get_block_epoch(); + + let address_info_mapper = self.address_info(&caller); + if address_info_mapper.is_empty() { + let address_info = AddressInfo::new_with_epoch(current_epoch); + self.address_info(&caller).set(address_info); + return; + } + + address_info_mapper.update(|address_info| { + require!( + address_info.last_epoch_claimed < current_epoch, + "epoch already claimed" + ); + + if address_info.last_epoch_claimed + 1 == current_epoch { + address_info.current_streak += 1; + } else { + address_info.current_streak = 1; + } + + address_info.total_epochs_claimed += 1; + address_info.last_epoch_claimed = current_epoch; + + if address_info.best_streak < address_info.current_streak { + address_info.best_streak = address_info.current_streak; + } + }); + } + + #[payable("*")] + #[endpoint(claimAndRepair)] + fn claim_and_repair(&self) { + let caller = self.blockchain().get_caller(); + require!( + !self.blockchain().is_smart_contract(&caller), + "Only user accounts can perform claim and repair" + ); + self.require_same_shard(&caller); + + let payment = self.call_value().single_esdt(); + let repair_streak_token_identifier = self.repair_streak_token_identifier().get(); + require!( + payment.token_identifier == repair_streak_token_identifier, + "Bad payment token" + ); + require!(payment.amount == SFT_AMOUNT, "Bad payment amount"); + + let current_epoch = self.blockchain().get_block_epoch(); + + let address_info_mapper = self.address_info(&caller); + + require!( + !address_info_mapper.is_empty(), + "can't repair streak for address" + ); + + address_info_mapper.update(|address_info| { + let missed_epochs = + self.get_missed_epochs(current_epoch, address_info.last_epoch_claimed); + + require!( + missed_epochs > 0 && missed_epochs <= MAX_REPAIR_GAP, + "can't repair streak for current epoch" + ); + + address_info.current_streak += missed_epochs + 1; + address_info.total_epochs_claimed += missed_epochs + 1; + address_info.last_epoch_claimed = current_epoch; + if address_info.best_streak < address_info.current_streak { + address_info.best_streak = address_info.current_streak; + } + }); + + self.send().esdt_local_burn( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + } + + #[endpoint(updateState)] + fn update_state( + &self, + address: &ManagedAddress, + current_streak: u64, + last_epoch_claimed: u64, + total_epochs_claimed: u64, + best_streak: u64, + ) { + self.require_caller_is_admin(); + self.require_same_shard(address); + + let address_info = AddressInfo::new( + current_streak, + last_epoch_claimed, + total_epochs_claimed, + best_streak, + ); + self.address_info(address).set(address_info); + } + + #[endpoint(setRepairStreakTokenId)] + fn set_repair_streak_token_id(&self, repair_streak_token_id: TokenIdentifier) { + self.require_caller_is_admin(); + + self.internal_set_repair_streak_token_id(repair_streak_token_id); + } + + fn internal_set_repair_streak_token_id(&self, repair_streak_token_id: TokenIdentifier) { + require!( + repair_streak_token_id.is_valid_esdt_identifier(), + "Invalid token ID" + ); + self.repair_streak_token_identifier() + .set(repair_streak_token_id); + } +} diff --git a/contracts/on-chain-claim/tests/tests.rs b/contracts/on-chain-claim/tests/tests.rs new file mode 100644 index 00000000..6a6a8efe --- /dev/null +++ b/contracts/on-chain-claim/tests/tests.rs @@ -0,0 +1,760 @@ +use config::ConfigModule; +use multiversx_sc::types::{ManagedAddress, TokenIdentifier}; +use multiversx_sc_modules::only_admin::OnlyAdminModule; +use multiversx_sc_scenario::{scenario_model::*, *}; +use on_chain_claim::*; + +const ON_CHAIN_CLAIM_PATH_EXPR: &str = "file:output/on-chain-claim.wasm"; +const TOKEN_IDENTIFIER: &str = "XREPAIR-abcdef"; +const OTHER_TOKEN_IDENTIFIER_EXPR: &str = "str:XREPAIRRR-abcdef"; +const TOKEN_IDENTIFIER_EXPR: &str = "str:XREPAIR-abcdef"; +const TOKEN_NONCE: u64 = 1; +const USER1_ADDR: &str = "address:user1"; +const OWNER_ADDR: &str = "address:owner"; +const SC_ADDR: &str = "sc:on-chain-claim"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/on-chain-claim"); + + blockchain.register_contract( + "file:output/on-chain-claim.wasm", + on_chain_claim::ContractBuilder, + ); + blockchain +} + +#[test] +fn check_token_identifier() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new().nonce(1).esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + sc.repair_streak_token_identifier() + .set(TokenIdentifier::from(TOKEN_IDENTIFIER)); + }, + ); +} + +#[test] +fn check_before_claim() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new().nonce(1).esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info_mapper = sc.address_info(managed_address); + + assert!(address_info_mapper.is_empty()); + }); +} + +#[test] +fn check_update_state() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new().nonce(1).esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info_mapper = sc.address_info(managed_address); + + assert!(address_info_mapper.is_empty()); + }) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + let address = AddressValue::from(OWNER_ADDR).to_address(); + let managed_address = ManagedAddress::from(address); + + sc.add_admin(managed_address); + }, + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(OWNER_ADDR), + |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + sc.update_state(managed_address, 5u64, 21u64, 7u64, 5u64); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + + assert_eq!(address_info.current_streak, 5); + assert_eq!(address_info.last_epoch_claimed, 21); + assert_eq!(address_info.total_epochs_claimed, 7); + }); +} + +#[test] +fn check_after_claim() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new().nonce(1).esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 1); + assert_eq!(address_info.last_epoch_claimed, 20); + }) + .set_state_step(SetStateStep::new().block_epoch(21)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + + assert_eq!(address_info.current_streak, 2); + assert_eq!(address_info.total_epochs_claimed, 2); + assert_eq!(address_info.last_epoch_claimed, 21); + }) + .set_state_step(SetStateStep::new().block_epoch(25)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 3); + assert_eq!(address_info.last_epoch_claimed, 25); + }); +} + +#[test] +fn check_claim_and_repair() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new() + .nonce(1) + .esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "100", + Option::Some(()), + ) + .esdt_nft_balance( + OTHER_TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + sc.repair_streak_token_identifier() + .set(TokenIdentifier::from(TOKEN_IDENTIFIER)); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info_mapper = sc.address_info(managed_address); + + assert!(address_info_mapper.is_empty()); + }) + .whitebox_call_check( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, 1, "1") + .no_expect(), + |sc| { + sc.claim_and_repair(); + }, + |r| { + r.assert_user_error("can't repair streak for address"); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info_mapper = sc.address_info(managed_address); + + assert!(address_info_mapper.is_empty()); + }) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 1); + assert_eq!(address_info.last_epoch_claimed, 20); + }) + .set_state_step(SetStateStep::new().block_epoch(21)) + .whitebox_call_check( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, TOKEN_NONCE, "1") + .no_expect(), + |sc| { + sc.claim_and_repair(); + }, + |r| { + r.assert_user_error("can't repair streak for current epoch"); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 1); + assert_eq!(address_info.last_epoch_claimed, 20); + }) + .set_state_step(SetStateStep::new().block_epoch(22)) + .whitebox_call_check( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(OTHER_TOKEN_IDENTIFIER_EXPR, 1, "1") + .no_expect(), + |sc| { + sc.claim_and_repair(); + }, + |r| { + r.assert_user_error("Bad payment token"); + }, + ) + .whitebox_call_check( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, TOKEN_NONCE, "2") + .no_expect(), + |sc| { + sc.claim_and_repair(); + }, + |r| { + r.assert_user_error("Bad payment amount"); + }, + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, 1, "1"), + |sc| { + sc.claim_and_repair(); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 3); + assert_eq!(address_info.total_epochs_claimed, 3); + assert_eq!(address_info.last_epoch_claimed, 22); + assert_eq!(address_info.best_streak, 3); + }) + .set_state_step(SetStateStep::new().block_epoch(28)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, 1, "1"), + |sc| { + sc.claim_and_repair(); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 9); + assert_eq!(address_info.total_epochs_claimed, 9); + assert_eq!(address_info.last_epoch_claimed, 28); + assert_eq!(address_info.best_streak, 9); + }) + .set_state_step(SetStateStep::new().block_epoch(35)) + .whitebox_call_check( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, TOKEN_NONCE, "1") + .no_expect(), + |sc| { + sc.claim_and_repair(); + }, + |r| { + r.assert_user_error("can't repair streak for current epoch"); + }, + ); +} + +#[test] +fn best_streak() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new().nonce(1).esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + sc.repair_streak_token_identifier() + .set(TokenIdentifier::from(TOKEN_IDENTIFIER)); + }, + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + let address = AddressValue::from(OWNER_ADDR).to_address(); + let managed_address = ManagedAddress::from(address); + + sc.add_admin(managed_address); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let repair_streak_token_identifier = sc.repair_streak_token_identifier().get(); + let identifier = TokenIdentifier::from(TOKEN_IDENTIFIER); + assert_eq!(repair_streak_token_identifier, identifier); + }) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 1); + assert_eq!(address_info.last_epoch_claimed, 20); + assert_eq!(address_info.best_streak, 1); + }) + .set_state_step(SetStateStep::new().block_epoch(21)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 2); + assert_eq!(address_info.total_epochs_claimed, 2); + assert_eq!(address_info.last_epoch_claimed, 21); + assert_eq!(address_info.best_streak, 2); + }) + .set_state_step(SetStateStep::new().block_epoch(25)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 3); + assert_eq!(address_info.last_epoch_claimed, 25); + assert_eq!(address_info.best_streak, 2); + }) + .set_state_step(SetStateStep::new().block_epoch(26)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 2); + assert_eq!(address_info.total_epochs_claimed, 4); + assert_eq!(address_info.last_epoch_claimed, 26); + assert_eq!(address_info.best_streak, 2); + }) + .set_state_step(SetStateStep::new().block_epoch(27)) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 3); + assert_eq!(address_info.total_epochs_claimed, 5); + assert_eq!(address_info.last_epoch_claimed, 27); + assert_eq!(address_info.best_streak, 3); + }); +} + +#[test] +fn on_chain_claim_whitebox() { + let mut world = world(); + let on_chain_claim_whitebox = WhiteboxContract::new(SC_ADDR, on_chain_claim::contract_obj); + let on_chain_claim_code = world.code_expression(ON_CHAIN_CLAIM_PATH_EXPR); + + let roles: Vec = vec!["ESDTRoleNFTBurn".to_string()]; + + world + .set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDR, Account::new().nonce(1)) + .put_account( + USER1_ADDR, + Account::new().nonce(1).esdt_nft_balance( + TOKEN_IDENTIFIER_EXPR, + TOKEN_NONCE, + "1", + Option::Some(()), + ), + ) + .put_account( + SC_ADDR, + Account::new() + .nonce(1) + .code(&on_chain_claim_code) + .owner(OWNER_ADDR) + .esdt_roles(TOKEN_IDENTIFIER_EXPR, roles), + ) + .block_epoch(20) + .new_address(OWNER_ADDR, TOKEN_NONCE, SC_ADDR), + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + sc.repair_streak_token_identifier() + .set(TokenIdentifier::from(TOKEN_IDENTIFIER)); + }, + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(SC_ADDR), + |sc| { + let address = AddressValue::from(OWNER_ADDR).to_address(); + let managed_address = ManagedAddress::from(address); + + sc.add_admin(managed_address); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let repair_streak_token_identifier = sc.repair_streak_token_identifier().get(); + let identifier = TokenIdentifier::from(TOKEN_IDENTIFIER); + assert_eq!(repair_streak_token_identifier, identifier); + }) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 1); + assert_eq!(address_info.last_epoch_claimed, 20); + }) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let can_be_repaired = sc.can_be_repaired(managed_address); + assert!(!can_be_repaired); + }) + .set_state_step(SetStateStep::new().block_epoch(21)) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let can_be_repaired = sc.can_be_repaired(managed_address); + assert!(!can_be_repaired); + }) + .set_state_step(SetStateStep::new().block_epoch(22)) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let can_be_repaired = sc.can_be_repaired(managed_address); + assert!(can_be_repaired); + }) + .set_state_step(SetStateStep::new().block_epoch(26)) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let can_be_repaired = sc.can_be_repaired(managed_address); + assert!(can_be_repaired); + }) + .set_state_step(SetStateStep::new().block_epoch(27)) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let can_be_repaired = sc.can_be_repaired(managed_address); + assert!(!can_be_repaired); + }) + .whitebox_call_check( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, 1, "1") + .no_expect(), + |sc| { + sc.claim_and_repair(); + }, + |r| { + r.assert_user_error("can't repair streak for current epoch"); + }, + ) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(USER1_ADDR), + |sc| sc.claim(), + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 1); + assert_eq!(address_info.total_epochs_claimed, 2); + assert_eq!(address_info.last_epoch_claimed, 27); + assert_eq!(address_info.best_streak, 1); + }) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new().from(OWNER_ADDR), + |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + sc.update_state(managed_address, 5u64, 21u64, 7u64, 5u64); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let can_be_repaired = sc.can_be_repaired(managed_address); + assert!(can_be_repaired); + }) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 5); + assert_eq!(address_info.total_epochs_claimed, 7); + assert_eq!(address_info.last_epoch_claimed, 21); + assert_eq!(address_info.best_streak, 5); + }) + .whitebox_call( + &on_chain_claim_whitebox, + ScCallStep::new() + .from(USER1_ADDR) + .to(SC_ADDR) + .esdt_transfer(TOKEN_IDENTIFIER_EXPR, 1, "1"), + |sc| { + sc.claim_and_repair(); + }, + ) + .whitebox_query(&on_chain_claim_whitebox, |sc| { + let address = AddressValue::from(USER1_ADDR).to_address(); + let managed_address = &ManagedAddress::from(address); + let address_info = sc.address_info(managed_address).get(); + assert_eq!(address_info.current_streak, 11); + assert_eq!(address_info.total_epochs_claimed, 13); + assert_eq!(address_info.last_epoch_claimed, 27); + assert_eq!(address_info.best_streak, 11); + }); +} diff --git a/contracts/on-chain-claim/wasm/Cargo.lock b/contracts/on-chain-claim/wasm/Cargo.lock new file mode 100644 index 00000000..8244ee9c --- /dev/null +++ b/contracts/on-chain-claim/wasm/Cargo.lock @@ -0,0 +1,190 @@ +# 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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[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.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c94b173dc5ff0e157f767275fe6b7a1b4d2ad343bef7b66cd22a6353e016b93" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19908153158c03df4582af08f47c0eb39fb52a7dff4736b301a66acbbb9955d3" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b03b43f9cad320992f54ed162de2ed63e3ec83ed01361e57ee9c1865fba5a2" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b78945957036c281ad6ee21bb5120dcefa2017688adf43ec94e3e7c982efb09" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c63ffaba95e630ff75981e2f5f50da64f523219b52f484234c66f3adc248885f" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9579f40c00da56a5a68e010ff851fa48ac7b9c6a16ad4314795cb32d889d9e78" +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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "on-chain-claim" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "on-chain-claim-wasm" +version = "0.0.0" +dependencies = [ + "multiversx-sc-wasm-adapter", + "on-chain-claim", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +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.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +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" diff --git a/contracts/on-chain-claim/wasm/Cargo.toml b/contracts/on-chain-claim/wasm/Cargo.toml new file mode 100644 index 00000000..de277e3a --- /dev/null +++ b/contracts/on-chain-claim/wasm/Cargo.toml @@ -0,0 +1,31 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "on-chain-claim-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 + +[dependencies.on-chain-claim] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.46.0" + +[workspace] +members = ["."] diff --git a/contracts/on-chain-claim/wasm/src/lib.rs b/contracts/on-chain-claim/wasm/src/lib.rs new file mode 100644 index 00000000..44912891 --- /dev/null +++ b/contracts/on-chain-claim/wasm/src/lib.rs @@ -0,0 +1,38 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 12 +// Async Callback (empty): 1 +// Total number of exported functions: 14 + +#![no_std] +#![allow(internal_features)] +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + on_chain_claim + ( + init => init + upgrade => upgrade + claim => claim + claimAndRepair => claim_and_repair + updateState => update_state + setRepairStreakTokenId => set_repair_streak_token_id + getAddressInfo => get_address_info + canBeRepaired => can_be_repaired + getRepairStreakTokenIdentifier => repair_streak_token_identifier + isAdmin => is_admin + addAdmin => add_admin + removeAdmin => remove_admin + getAdmins => admins + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {}