Skip to content

Commit

Permalink
Max Supply
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeHartnell authored and Jake Hartnell committed Mar 26, 2024
1 parent ea21f4f commit 9f39048
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 31 deletions.
4 changes: 2 additions & 2 deletions contracts/external/cw-abc/src/abc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ pub struct SupplyToken {
/// Number of decimal places for the supply token, needed for proper curve math.
/// Default for token factory is 6
pub decimals: u8,
// TODO max supply
// pub max_supply: Uint128,
// Optional maximum supply
pub max_supply: Option<Uint128>,
}

#[cw_serde]
Expand Down
17 changes: 12 additions & 5 deletions contracts/external/cw-abc/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ use std::collections::HashSet;
use std::ops::Deref;
use token_bindings::{TokenFactoryMsg, TokenFactoryQuery};

use crate::abc::{CommonsPhase, CurveFn, MinMax};
use crate::abc::CommonsPhase;
use crate::contract::CwAbcResult;
use crate::msg::UpdatePhaseConfigMsg;
use crate::state::{
CURVE_STATE, CURVE_TYPE, DONATIONS, HATCHERS, HATCHER_ALLOWLIST, PHASE, PHASE_CONFIG,
SUPPLY_DENOM, TOKEN_ISSUER_CONTRACT,
CURVE_STATE, CURVE_TYPE, DONATIONS, HATCHERS, HATCHER_ALLOWLIST, MAX_SUPPLY, PHASE,
PHASE_CONFIG, SUPPLY_DENOM, TOKEN_ISSUER_CONTRACT,
};
use crate::ContractError;

Expand Down Expand Up @@ -81,6 +81,15 @@ pub fn execute_buy(deps: DepsMut<TokenFactoryQuery>, _env: Env, info: MessageInf
let minted = new_supply
.checked_sub(curve_state.supply)
.map_err(StdError::overflow)?;

// Check that the minted amount has not exceeded the max supply (if configured)
if let Some(max_supply) = MAX_SUPPLY.may_load(deps.storage)? {
if new_supply > max_supply {
return Err(ContractError::CannotExceedMaxSupply { max: max_supply });
}
}

// Save the new curve state
curve_state.supply = new_supply;
CURVE_STATE.save(deps.storage, &curve_state)?;

Expand All @@ -95,8 +104,6 @@ pub fn execute_buy(deps: DepsMut<TokenFactoryQuery>, _env: Env, info: MessageInf
funds: vec![],
};

// TODO check that the minted amount has not exceeded the max supply

Ok(Response::new()
.add_message(mint_msg)
.add_attribute("action", "buy")
Expand Down
17 changes: 5 additions & 12 deletions contracts/external/cw-abc/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use crate::curves::DecimalPlaces;
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, UpdatePhaseConfigMsg};
use crate::state::{
CurveState, CURVE_STATE, CURVE_TYPE, HATCHER_ALLOWLIST, PHASE, PHASE_CONFIG, SUPPLY_DENOM,
TOKEN_INSTANTIATION_INFO, TOKEN_ISSUER_CONTRACT,
CurveState, CURVE_STATE, CURVE_TYPE, HATCHER_ALLOWLIST, MAX_SUPPLY, PHASE, PHASE_CONFIG,
SUPPLY_DENOM, TOKEN_INSTANTIATION_INFO, TOKEN_ISSUER_CONTRACT,
};
use crate::{commands, queries};

Expand Down Expand Up @@ -62,16 +62,9 @@ pub fn instantiate(
// Save new token info for use in reply
TOKEN_INSTANTIATION_INFO.save(deps.storage, &supply)?;

// Save the denom
SUPPLY_DENOM.save(
deps.storage,
&format!(
"{}/{}/{}",
DENOM_PREFIX,
env.contract.address.into_string(),
supply.subdenom
),
)?;
if let Some(max_supply) = supply.max_supply {
MAX_SUPPLY.save(deps.storage, &max_supply)?;
}

// Save the curve type and state
let normalization_places = DecimalPlaces::new(supply.decimals, reserve.decimals);
Expand Down
10 changes: 5 additions & 5 deletions contracts/external/cw-abc/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ pub enum ContractError {
#[error("{0}")]
Ownership(#[from] cw_ownable::OwnershipError),

#[error("Cannot mint more tokens than the maximum supply of {max}")]
CannotExceedMaxSupply { max: Uint128 },

#[error("The commons is closed to new contributions")]
CommonsClosed {},

#[error("Contribution must be less than or equal to {max} and greater than or equal to {min}")]
ContributionLimit { min: Uint128, max: Uint128 },

#[error("Selling is disabled during the hatch phase")]
HatchSellingDisabled {},
#[error("Hatch phase config error {0}")]
HatchPhaseConfigError(String),

#[error("Invalid subdenom: {subdenom:?}")]
InvalidSubdenom { subdenom: String },
Expand All @@ -34,9 +37,6 @@ pub enum ContractError {
#[error("Invalid sell amount")]
MismatchedSellAmount {},

#[error("Hatch phase config error {0}")]
HatchPhaseConfigError(String),

#[error("Open phase config error {0}")]
OpenPhaseConfigError(String),

Expand Down
3 changes: 3 additions & 0 deletions contracts/external/cw-abc/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub const CURVE_TYPE: Item<CurveType> = Item::new("curve_type");
/// The denom used for the supply token
pub const SUPPLY_DENOM: Item<String> = Item::new("denom");

/// The maximum supply of the supply token, new tokens cannot be minted beyond this cap
pub const MAX_SUPPLY: Item<Uint128> = Item::new("max_supply");

/// Hatcher phase allowlist
/// TODO: we could use the keys for the [`HATCHERS`] map instead setting them to 0 at the beginning, though existing hatchers would not be able to be removed
pub static HATCHER_ALLOWLIST: Item<HashSet<Addr>> = Item::new("hatch_allowlist");
Expand Down
36 changes: 29 additions & 7 deletions contracts/external/cw-abc/src/test_tube/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::{
abc::{
ClosedConfig, CommonsPhase, CommonsPhaseConfig, CurveType, HatchConfig, MinMax, OpenConfig,
ReserveToken, SupplyToken,
},
abc::{ClosedConfig, CommonsPhase, CommonsPhaseConfig, HatchConfig, MinMax, OpenConfig},
msg::{
CommonsPhaseConfigResponse, CurveInfoResponse, DenomResponse, ExecuteMsg, InstantiateMsg,
QueryMsg,
Expand Down Expand Up @@ -216,8 +213,33 @@ fn test_contribution_limits_enforced() {
);
}

// TODO
#[test]
fn test_max_supply() {
// Set a max supply and ensure it does not go over
fn test_max_supply_enforced() {
let app = OsmosisTestApp::new();
let builder = TestEnvBuilder::new();
let env = builder.default_setup(&app);
let TestEnv {
ref abc,
ref accounts,
..
} = env;

// Buy enough tokens to end the hatch phase
abc.execute(&ExecuteMsg::Buy {}, &coins(1000000, RESERVE), &accounts[0])
.unwrap();

// Buy enough tokens to trigger a max supply error
let err = abc
.execute(
&ExecuteMsg::Buy {},
&coins(1000000000, RESERVE),
&accounts[0],
)
.unwrap_err();
assert_eq!(
err,
abc.execute_error(ContractError::CannotExceedMaxSupply {
max: Uint128::from(1000000u128)
})
);
}
1 change: 1 addition & 0 deletions contracts/external/cw-abc/src/test_tube/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl TestEnvBuilder {
subdenom: DENOM.to_string(),
metadata: None,
decimals: 6,
max_supply: Some(Uint128::from(1000000000u128)),
},
reserve: ReserveToken {
denom: RESERVE.to_string(),
Expand Down
1 change: 1 addition & 0 deletions contracts/external/cw-abc/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub fn default_instantiate_msg(
subdenom: TEST_SUPPLY_DENOM.to_string(),
metadata: Some(default_supply_metadata()),
decimals,
max_supply: None,
},
reserve: ReserveToken {
denom: TEST_RESERVE_DENOM.to_string(),
Expand Down

0 comments on commit 9f39048

Please sign in to comment.