Skip to content

Commit

Permalink
Merge pull request #29 from blend-capital/constructors
Browse files Browse the repository at this point in the history
Constructors
  • Loading branch information
mootz12 authored Jan 13, 2025
2 parents 8acb517 + a91b24a commit ee643b9
Show file tree
Hide file tree
Showing 47 changed files with 504 additions and 2,344 deletions.
14 changes: 3 additions & 11 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ resolver = "2"
members = [
"backstop",
"blend-contract-sdk",
"emitter",
"pool",
"mocks/mock-pool-factory",
"pool-factory",
Expand Down
8 changes: 0 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ test: build

build:
cargo build -p blend-contract-sdk
cargo rustc --manifest-path=emitter/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
cargo rustc --manifest-path=pool-factory/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
cargo rustc --manifest-path=backstop/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
cargo rustc --manifest-path=pool/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
mkdir -p target/wasm32-unknown-unknown/optimized
stellar contract optimize \
--wasm target/wasm32-unknown-unknown/release/emitter.wasm \
--wasm-out target/wasm32-unknown-unknown/optimized/emitter.wasm
stellar contract optimize \
--wasm target/wasm32-unknown-unknown/release/pool_factory.wasm \
--wasm-out target/wasm32-unknown-unknown/optimized/pool_factory.wasm
Expand All @@ -38,10 +34,6 @@ generate-js:
--contract-id CBWH54OKUK6U2J2A4J2REJEYB625NEFCHISWXLOPR2D2D6FTN63TJTWN \
--wasm ./target/wasm32-unknown-unknown/optimized/backstop.wasm --output-dir ./js/js-backstop/ \
--rpc-url http://localhost:8000 --network-passphrase "Standalone Network ; February 2017" --network Standalone
stellar contract bindings typescript --overwrite \
--contract-id CBWH54OKUK6U2J2A4J2REJEYB625NEFCHISWXLOPR2D2D6FTN63TJTWN \
--wasm ./target/wasm32-unknown-unknown/optimized/emitter.wasm --output-dir ./js/js-emitter/ \
--rpc-url http://localhost:8000 --network-passphrase "Standalone Network ; February 2017" --network Standalone
stellar contract bindings typescript --overwrite \
--contract-id CBWH54OKUK6U2J2A4J2REJEYB625NEFCHISWXLOPR2D2D6FTN63TJTWN \
--wasm ./target/wasm32-unknown-unknown/optimized/pool_factory.wasm --output-dir ./js/js-pool-factory/ \
Expand Down
2 changes: 1 addition & 1 deletion backstop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ sep-41-token = { workspace = true }
[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
mock-pool-factory = { path = "../mocks/mock-pool-factory", features = ["testutils"] }
emitter = { path = "../emitter", features = ["testutils"] }
sep-41-token = { workspace = true, features = ["testutils"] }
blend-contract-sdk = { path = "../blend-contract-sdk", features = ["testutils"] }
64 changes: 18 additions & 46 deletions backstop/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,6 @@ pub struct BackstopContract;

#[contractclient(name = "BackstopClient")]
pub trait Backstop {
/// Initialize the backstop
///
/// This function requires that the Emitter has already been initialized
///
/// ### Arguments
/// * `backstop_token` - The backstop token ID - an LP token with the pair BLND:USDC
/// * `emitter` - The Emitter contract ID
/// * `blnd_token` - The BLND token ID
/// * `usdc_token` - The USDC token ID
/// * `pool_factory` - The pool factory ID
/// * `drop_list` - The list of addresses to distribute initial BLND to and the percent of the distribution they should receive
///
/// ### Errors
/// If initialize has already been called
fn initialize(
e: Env,
backstop_token: Address,
emitter: Address,
blnd_token: Address,
usdc_token: Address,
pool_factory: Address,
drop_list: Vec<(Address, i128)>,
);

/********** Core **********/

/// Deposit backstop tokens from "from" into the backstop of a pool
Expand Down Expand Up @@ -190,44 +166,40 @@ pub trait Backstop {
fn update_tkn_val(e: Env) -> (i128, i128);
}

/// @dev
/// The contract implementation only manages the authorization / authentication required from the caller(s), and
/// utilizes other modules to carry out contract functionality.
#[contractimpl]
impl Backstop for BackstopContract {
fn initialize(
impl BackstopContract {
/// Construct the backstop contract
///
/// ### Arguments
/// * `backstop_token` - The backstop token ID - an LP token with the pair BLND:USDC
/// * `emitter` - The Emitter contract ID
/// * `blnd_token` - The BLND token ID
/// * `usdc_token` - The USDC token ID
/// * `pool_factory` - The pool factory ID
/// * `drop_list` - The list of addresses to distribute initial BLND to and the percent of the distribution they should receive
pub fn __constructor(
e: Env,
backstop_token: Address,
emitter: Address,
usdc_token: Address,
blnd_token: Address,
usdc_token: Address,
pool_factory: Address,
drop_list: Vec<(Address, i128)>,
) {
storage::extend_instance(&e);
if storage::get_is_init(&e) {
panic_with_error!(e, BackstopError::AlreadyInitializedError);
}

storage::set_backstop_token(&e, &backstop_token);
storage::set_blnd_token(&e, &blnd_token);
storage::set_usdc_token(&e, &usdc_token);
storage::set_pool_factory(&e, &pool_factory);
// NOTE: For a replacement backstop, this value likely needs to be stored in persistent storage to avoid
// an expiration occuring before a backstop swap is finalized.
storage::set_drop_list(&e, &drop_list);
storage::set_emitter(&e, &emitter);

// fetch last distribution time from emitter
// NOTE: For a replacement backstop, this must be fetched after the swap is completed, but this is
// a shortcut for the first backstop.
let last_distribution_time =
EmitterClient::new(&e, &emitter).get_last_distro(&e.current_contract_address());
storage::set_last_distribution_time(&e, &last_distribution_time);

storage::set_is_init(&e);
}
}

/// @dev
/// The contract implementation only manages the authorization / authentication required from the caller(s), and
/// utilizes other modules to carry out contract functionality.
#[contractimpl]
impl Backstop for BackstopContract {
/********** Core **********/

fn deposit(e: Env, from: Address, pool_address: Address, amount: i128) -> i128 {
Expand Down
2 changes: 1 addition & 1 deletion backstop/src/dependencies/emitter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
use soroban_sdk::contractimport;

contractimport!(file = "../target/wasm32-unknown-unknown/release/emitter.wasm");
contractimport!(file = "../blend-contract-sdk/wasm/emitter.wasm");
87 changes: 83 additions & 4 deletions backstop/src/emissions/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,24 @@ fn remove_pool(e: &Env, reward_zone: &mut Vec<Address>, to_remove: &Address) {
}

pub fn distribute(e: &Env) -> i128 {
let emitter = storage::get_emitter(e);
let emitter_last_distribution =
EmitterClient::new(&e, &emitter).get_last_distro(&e.current_contract_address());
let last_distribution = storage::get_last_distribution_time(e);

// if we have never distributed before, record the emitter's last distribution time and
// start emissions from that time
if last_distribution == 0 {
storage::set_last_distribution_time(e, &emitter_last_distribution);
return 0;
}

let reward_zone = storage::get_reward_zone(e);
let rz_len = reward_zone.len();
// reward zone must have at least one pool for emissions to start
if rz_len == 0 {
panic_with_error!(e, BackstopError::BadRequest);
}
let emitter = storage::get_emitter(e);
let emitter_last_distribution =
EmitterClient::new(&e, &emitter).get_last_distro(&e.current_contract_address());
let last_distribution = storage::get_last_distribution_time(e);

// ensure enough time has passed between the last emitter distribution and gulp_emissions
// to prevent excess rounding issues
Expand Down Expand Up @@ -489,6 +497,8 @@ mod tests {

let gulp_index = storage::get_rz_emission_index(&e);
assert_eq!(gulp_index, 8640000000000);
let last_distro_time = storage::get_last_distribution_time(&e);
assert_eq!(last_distro_time, emitter_distro_time);
});
}

Expand Down Expand Up @@ -716,6 +726,75 @@ mod tests {
});
}

#[test]
fn test_distribute_no_last_dist_time() {
let e = Env::default();
e.cost_estimate().budget().reset_unlimited();

e.ledger().set(LedgerInfo {
timestamp: 1713139200,
protocol_version: 22,
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
min_temp_entry_ttl: 10,
min_persistent_entry_ttl: 10,
max_entry_ttl: 3110400,
});

let backstop = create_backstop(&e);
let emitter_distro_time = 1713139200 - 10;
create_emitter(
&e,
&backstop,
&Address::generate(&e),
&Address::generate(&e),
emitter_distro_time,
);

let pool_1 = Address::generate(&e);
let pool_2 = Address::generate(&e);
let pool_3 = Address::generate(&e);
let reward_zone: Vec<Address> = vec![&e, pool_1.clone(), pool_2.clone(), pool_3.clone()];

e.as_contract(&backstop, || {
storage::set_reward_zone(&e, &reward_zone);
storage::set_pool_balance(
&e,
&pool_1,
&PoolBalance {
tokens: 300_000_0000000,
shares: 200_000_0000000,
q4w: 0,
},
);
storage::set_pool_balance(
&e,
&pool_2,
&PoolBalance {
tokens: 200_000_0000000,
shares: 150_000_0000000,
q4w: 0,
},
);
storage::set_pool_balance(
&e,
&pool_3,
&PoolBalance {
tokens: 500_000_0000000,
shares: 600_000_0000000,
q4w: 0,
},
);

let new_emissions = distribute(&e);

assert_eq!(new_emissions, 0);
let last_distro_time = storage::get_last_distribution_time(&e);
assert_eq!(last_distro_time, emitter_distro_time);
});
}

/********** add_to_reward_zone **********/

#[test]
Expand Down
19 changes: 3 additions & 16 deletions backstop/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ pub struct UserEmissionData {

/********** Storage Key Types **********/

const IS_INIT_KEY: &str = "IsInit";
const EMITTER_KEY: &str = "Emitter";
const BACKSTOP_TOKEN_KEY: &str = "BToken";
const POOL_FACTORY_KEY: &str = "PoolFact";
Expand Down Expand Up @@ -113,18 +112,6 @@ fn get_persistent_default<K: IntoVal<Env, Val>, V: TryFromVal<Env, Val>, F: FnOn

/********** Instance Storage **********/

/// Check if the contract has been initialized
pub fn get_is_init(e: &Env) -> bool {
e.storage().instance().has(&Symbol::new(e, IS_INIT_KEY))
}

/// Set the contract as initialized
pub fn set_is_init(e: &Env) {
e.storage()
.instance()
.set::<Symbol, bool>(&Symbol::new(e, IS_INIT_KEY), &true);
}

/// Fetch the pool factory id
pub fn get_emitter(e: &Env) -> Address {
e.storage()
Expand Down Expand Up @@ -471,7 +458,7 @@ pub fn set_user_emis_data(
/// Get the current pool addresses that are in the drop list and the amount of the initial distribution they receive
pub fn get_drop_list(e: &Env) -> Vec<(Address, i128)> {
e.storage()
.temporary()
.persistent()
.get::<Symbol, Vec<(Address, i128)>>(&Symbol::new(&e, DROP_LIST_KEY))
.unwrap_optimized()
}
Expand All @@ -482,9 +469,9 @@ pub fn get_drop_list(e: &Env) -> Vec<(Address, i128)> {
/// * `drop_list` - The map of pool addresses to the amount of the initial distribution they receive
pub fn set_drop_list(e: &Env, drop_list: &Vec<(Address, i128)>) {
e.storage()
.temporary()
.persistent()
.set::<Symbol, Vec<(Address, i128)>>(&Symbol::new(&e, DROP_LIST_KEY), drop_list);
e.storage().temporary().extend_ttl(
e.storage().persistent().extend_ttl(
&Symbol::new(&e, DROP_LIST_KEY),
LEDGER_THRESHOLD_USER,
LEDGER_BUMP_USER,
Expand Down
Loading

0 comments on commit ee643b9

Please sign in to comment.