Skip to content

Commit

Permalink
burn implemented
Browse files Browse the repository at this point in the history
Co-authored-by: igor-casper <[email protected]>
  • Loading branch information
hoffmannjan and igor-casper committed Apr 11, 2024
1 parent 5120537 commit c519036
Show file tree
Hide file tree
Showing 17 changed files with 455 additions and 28 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions execution_engine/src/runtime/mint_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ where
ProviderError::AddressableEntityByAccountHash(account_hash)
})
}

fn is_valid_uref(&self, uref: &URef) -> bool {
self.context.access_rights().has_access_rights_to_uref(uref)
}
}

// TODO: update Mint + StorageProvider to better handle errors
Expand Down
8 changes: 8 additions & 0 deletions execution_engine/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,14 @@ where
let result: Result<(), mint::Error> = mint_runtime.reduce_total_supply(amount);
CLValue::from_t(result).map_err(Self::reverter)
})(),
mint::METHOD_BURN => (|| {
mint_runtime.charge_system_contract_call(mint_costs.burn)?;

let purse: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
let result: Result<(), mint::Error> = mint_runtime.burn(purse, amount);
CLValue::from_t(result).map_err(Self::reverter)
})(),
// Type: `fn create() -> URef`
mint::METHOD_CREATE => (|| {
mint_runtime.charge_system_contract_call(mint_costs.create)?;
Expand Down
4 changes: 2 additions & 2 deletions execution_engine/src/runtime_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ where
}

/// Validates whether keys used in the `value` are not forged.
fn validate_value(&self, value: &StoredValue) -> Result<(), ExecError> {
pub(crate) fn validate_value(&self, value: &StoredValue) -> Result<(), ExecError> {
match value {
StoredValue::CLValue(cl_value) => self.validate_cl_value(cl_value),
StoredValue::Account(_) => Ok(()),
Expand Down Expand Up @@ -743,7 +743,7 @@ where
}

/// Validates if a [`Key`] refers to a [`URef`] and has a write bit set.
fn validate_writeable(&self, key: &Key) -> Result<(), ExecError> {
pub(crate) fn validate_writeable(&self, key: &Key) -> Result<(), ExecError> {
if self.is_writeable(key) {
Ok(())
} else {
Expand Down
216 changes: 216 additions & 0 deletions execution_engine_testing/tests/src/test/system_contracts/mint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use casper_engine_test_support::{
auction, ExecuteRequestBuilder, LmdbWasmTestBuilder, DEFAULT_ACCOUNT_ADDR,
};
use casper_types::{runtime_args, ProtocolVersion, URef, U512};

use tempfile::TempDir;

const TEST_DELEGATOR_INITIAL_ACCOUNT_BALANCE: u64 = 1_000_000 * 1_000_000_000;

const CONTRACT_BURN: &str = "burn.wasm";
const CONTRACT_TRANSFER_TO_NAMED_PURSE: &str = "transfer_to_named_purse.wasm";

const ARG_AMOUNT: &str = "amount";

const ARG_PURSE_NAME: &str = "purse_name";

#[ignore]
#[test]
fn should_empty_purse_when_burning_above_balance() {
let data_dir = TempDir::new().expect("should create temp dir");
let mut builder = LmdbWasmTestBuilder::new(data_dir.as_ref());
let source = *DEFAULT_ACCOUNT_ADDR;

let delegator_keys = auction::generate_public_keys(1);
let validator_keys = auction::generate_public_keys(1);

auction::run_genesis_and_create_initial_accounts(
&mut builder,
&validator_keys,
delegator_keys
.iter()
.map(|public_key| public_key.to_account_hash())
.collect::<Vec<_>>(),
U512::from(TEST_DELEGATOR_INITIAL_ACCOUNT_BALANCE),
);

let initial_supply = builder.total_supply(None);
let purse_name = "purse";
let purse_amount = U512::from(10_000_000_000u64);

// Create purse and transfer tokens to it
let exec_request = ExecuteRequestBuilder::standard(
source,
CONTRACT_TRANSFER_TO_NAMED_PURSE,
runtime_args! {
ARG_PURSE_NAME => purse_name,
ARG_AMOUNT => purse_amount,
},
)
.build();

builder.exec(exec_request).expect_success().commit();

let account = builder
.get_entity_with_named_keys_by_account_hash(source)
.expect("should have account");

let purse_uref: URef = account
.named_keys()
.get(purse_name)
.unwrap()
.into_uref()
.expect("should be uref");

assert_eq!(
builder
.get_purse_balance_result(ProtocolVersion::V2_0_0, purse_uref)
.motes()
.cloned()
.unwrap(),
purse_amount
);

// Burn part of tokens in a purse
let num_of_tokens_to_burn = U512::from(2_000_000_000u64);
let num_of_tokens_after_burn = U512::from(8_000_000_000u64);

let exec_request = ExecuteRequestBuilder::standard(
source,
CONTRACT_BURN,
runtime_args! {
ARG_PURSE_NAME => purse_name,
ARG_AMOUNT => num_of_tokens_to_burn,
},
)
.build();

builder.exec(exec_request).expect_success().commit();

assert_eq!(
builder
.get_purse_balance_result(ProtocolVersion::V2_0_0, purse_uref)
.motes()
.cloned()
.unwrap(),
num_of_tokens_after_burn
);

// Burn rest of tokens in a purse
let num_of_tokens_to_burn = U512::from(8_000_000_000u64);
let num_of_tokens_after_burn = U512::zero();

let exec_request = ExecuteRequestBuilder::standard(
source,
CONTRACT_BURN,
runtime_args! {
ARG_PURSE_NAME => purse_name,
ARG_AMOUNT => num_of_tokens_to_burn,
},
)
.build();

builder.exec(exec_request).expect_success().commit();

assert_eq!(
builder
.get_purse_balance_result(ProtocolVersion::V2_0_0, purse_uref)
.motes()
.cloned()
.unwrap(),
num_of_tokens_after_burn
);

let supply_after_burns = builder.total_supply(None);
let expected_supply_after_burns = initial_supply - U512::from(10_000_000_000u64);

assert_eq!(supply_after_burns, expected_supply_after_burns);
}

#[ignore]
#[test]
fn should_not_burn_excess_tokens() {
let data_dir = TempDir::new().expect("should create temp dir");
let mut builder = LmdbWasmTestBuilder::new(data_dir.as_ref());
let source = *DEFAULT_ACCOUNT_ADDR;

let delegator_keys = auction::generate_public_keys(1);
let validator_keys = auction::generate_public_keys(1);

auction::run_genesis_and_create_initial_accounts(
&mut builder,
&validator_keys,
delegator_keys
.iter()
.map(|public_key| public_key.to_account_hash())
.collect::<Vec<_>>(),
U512::from(TEST_DELEGATOR_INITIAL_ACCOUNT_BALANCE),
);

let initial_supply = builder.total_supply(None);
let purse_name = "purse";
let purse_amount = U512::from(10_000_000_000u64);

// Create purse and transfer tokens to it
let exec_request = ExecuteRequestBuilder::standard(
source,
CONTRACT_TRANSFER_TO_NAMED_PURSE,
runtime_args! {
ARG_PURSE_NAME => purse_name,
ARG_AMOUNT => purse_amount,
},
)
.build();

builder.exec(exec_request).expect_success().commit();

let account = builder
.get_entity_with_named_keys_by_account_hash(source)
.expect("should have account");

let purse_uref: URef = account
.named_keys()
.get(purse_name)
.unwrap()
.into_uref()
.expect("should be uref");

assert_eq!(
builder
.get_purse_balance_result(ProtocolVersion::V2_0_0, purse_uref)
.motes()
.cloned()
.unwrap(),
purse_amount
);

// Try to burn more then in a purse
let num_of_tokens_to_burn = U512::MAX;
let num_of_tokens_after_burn = U512::zero();

let exec_request = ExecuteRequestBuilder::standard(
source,
CONTRACT_BURN,
runtime_args! {
ARG_PURSE_NAME => purse_name,
ARG_AMOUNT => num_of_tokens_to_burn,
},
)
.build();

builder.exec(exec_request).expect_success().commit();

assert_eq!(
builder
.get_purse_balance_result(ProtocolVersion::V2_0_0, purse_uref)
.motes()
.cloned()
.unwrap(),
num_of_tokens_after_burn,
);

let supply_after_burns = builder.total_supply(None);
let expected_supply_after_burns = initial_supply - U512::from(10_000_000_000u64);

assert_eq!(supply_after_burns, expected_supply_after_burns);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ mod auction;
mod auction_bidding;
mod genesis;
mod handle_payment;
mod mint;
mod standard_payment;
mod upgrade;
3 changes: 2 additions & 1 deletion resources/local/chainspec.toml.in
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ mint = 2_500_000_000
reduce_total_supply = 10_000
create = 2_500_000_000
balance = 10_000
burn = 10_000
transfer = 10_000
read_base_round_reward = 10_000
mint_into_existing_purse = 2_500_000_000
Expand All @@ -313,4 +314,4 @@ pay = 10_000
upper_threshold = 90
lower_threshold = 50
max_gas_price = 3
min_gas_price = 1
min_gas_price = 1
3 changes: 2 additions & 1 deletion resources/production/chainspec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ mint = 2_500_000_000
reduce_total_supply = 10_000
create = 2_500_000_000
balance = 10_000
burn = 10_000
transfer = 10_000
read_base_round_reward = 10_000
mint_into_existing_purse = 2_500_000_000
Expand All @@ -324,4 +325,4 @@ pay = 10_000
upper_threshold = 90
lower_threshold = 50
max_gas_price = 3
min_gas_price = 1
min_gas_price = 1
16 changes: 16 additions & 0 deletions smart_contracts/contracts/client/burn/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "burn"
version = "0.1.0"
authors = ["Igor Bunar <[email protected]>", "Jan Hoffmann <[email protected]>"]
edition = "2021"

[[bin]]
name = "burn"
path = "src/main.rs"
bench = false
doctest = false
test = false

[dependencies]
casper-contract = { path = "../../../contract" }
casper-types = { path = "../../../../types" }
Loading

0 comments on commit c519036

Please sign in to comment.