Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: logging events and minor authorization updates #144

Merged
merged 3 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/borrow-operations-contract/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ name = "borrow-operations-contract"
[dependencies]
libraries = { path = "../../libraries" }
standards = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.6.1" }
sway_libs = { git = "https://github.com/FuelLabs/sway-libs", tag = "v0.23.1" }
26 changes: 26 additions & 0 deletions contracts/borrow-operations-contract/src/events.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
library;

pub struct OpenTroveEvent {
pub user: Identity,
pub asset_id: AssetId,
pub collateral: u64,
pub debt: u64,
}

pub struct AdjustTroveEvent {
pub user: Identity,
pub asset_id: AssetId,
pub collateral_change: u64,
pub debt_change: u64,
pub is_collateral_increase: bool,
pub is_debt_increase: bool,
pub total_collateral: u64,
pub total_debt: u64,
}

pub struct CloseTroveEvent {
pub user: Identity,
pub asset_id: AssetId,
pub collateral: u64,
pub debt: u64,
}
45 changes: 45 additions & 0 deletions contracts/borrow-operations-contract/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ contract;
// - Enforcing system parameters and stability conditions

mod data_structures;
mod events;

use standards::{src3::SRC3,};
use ::data_structures::{AssetContracts, LocalVariablesAdjustTrove, LocalVariablesOpenTrove};
use ::events::{AdjustTroveEvent, CloseTroveEvent, OpenTroveEvent};
use libraries::trove_manager_interface::data_structures::Status;
use libraries::active_pool_interface::ActivePool;
use libraries::token_interface::Token;
Expand All @@ -24,6 +26,7 @@ use libraries::coll_surplus_pool_interface::CollSurplusPool;
use libraries::oracle_interface::Oracle;
use libraries::borrow_operations_interface::BorrowOperations;
use libraries::fluid_math::*;
use sway_libs::ownership::*;
use std::{
asset::transfer,
auth::msg_sender,
Expand All @@ -34,6 +37,7 @@ use std::{
msg_amount,
},
hash::*,
logging::log,
};

configurable {
Expand Down Expand Up @@ -90,9 +94,28 @@ impl BorrowOperations for Contract {
.usdf_asset_id
.write(AssetId::new(usdf_contract, SubId::zero()));
storage.pauser.write(msg_sender().unwrap());
initialize_ownership(msg_sender().unwrap());
storage.is_initialized.write(true);
}

#[storage(read, write)]
fn set_pauser(pauser: Identity) {
only_owner();
storage.pauser.write(pauser);
}

#[storage(read, write)]
fn transfer_owner(new_owner: Identity) {
only_owner();
transfer_ownership(new_owner);
}

#[storage(read, write)]
fn renounce_owner() {
only_owner();
renounce_ownership();
}

// --- Borrower Trove Operations ---
// Open a new trove by borrowing USDF
// Differences from Liquity:0% frontend fees, no recovery mode, no gas compensation
Expand Down Expand Up @@ -138,6 +161,12 @@ impl BorrowOperations for Contract {
usdf_contract,
asset_contract,
);
log(OpenTroveEvent {
user: sender,
asset_id: asset_contract,
collateral: msg_amount(),
debt: vars.net_debt,
});
}
// Add collateral to an existing trove
#[storage(read, write), payable]
Expand Down Expand Up @@ -265,6 +294,12 @@ impl BorrowOperations for Contract {
transfer(borrower, usdf_asset_id, excess_usdf_returned);
}

log(CloseTroveEvent {
user: borrower,
asset_id: asset_contract,
collateral: coll,
debt: debt,
});
storage.lock_close_trove.write(false);
}
// Claim collateral from liquidations
Expand Down Expand Up @@ -435,6 +470,16 @@ fn internal_adjust_trove(
usdf_contract_cache,
);

log(AdjustTroveEvent {
user: borrower,
asset_id: asset,
collateral_change: vars.coll_change,
debt_change: vars.net_debt_change,
is_collateral_increase: vars.is_coll_increase,
is_debt_increase: is_debt_increase,
total_collateral: new_position_res.0,
total_debt: new_position_res.1,
});
storage.lock_internal_adjust_trove.write(false);
}

Expand Down
231 changes: 231 additions & 0 deletions contracts/borrow-operations-contract/tests/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
use fuels::{prelude::*, types::Identity};

use test_utils::{
data_structures::PRECISION,
interfaces::{
borrow_operations::{borrow_operations_abi, BorrowOperations},
oracle::oracle_abi,
pyth_oracle::{pyth_oracle_abi, pyth_price_feed, PYTH_TIMESTAMP},
token::token_abi,
},
setup::common::setup_protocol,
utils::with_min_borrow_fee,
};

#[tokio::test]
async fn test_trove_events() {
let (contracts, admin, wallets) = setup_protocol(4, false, false).await;

// Setup initial conditions
token_abi::mint_to_id(
&contracts.asset_contracts[0].asset,
5000 * PRECISION,
Identity::Address(admin.address().into()),
)
.await;

let deposit_amount = 1200 * PRECISION;
let borrow_amount = 600 * PRECISION;
let additional_collateral = 300 * PRECISION;

// Set oracle price
oracle_abi::set_debug_timestamp(&contracts.asset_contracts[0].oracle, PYTH_TIMESTAMP).await;
pyth_oracle_abi::update_price_feeds(
&contracts.asset_contracts[0].mock_pyth_oracle,
pyth_price_feed(1),
)
.await;

// Test OpenTroveEvent
let response = borrow_operations_abi::open_trove(
&contracts.borrow_operations,
&contracts.asset_contracts[0].oracle,
&contracts.asset_contracts[0].mock_pyth_oracle,
&contracts.asset_contracts[0].mock_redstone_oracle,
&contracts.asset_contracts[0].asset,
&contracts.usdf,
&contracts.fpt_staking,
&contracts.sorted_troves,
&contracts.asset_contracts[0].trove_manager,
&contracts.active_pool,
deposit_amount,
borrow_amount,
Identity::Address(Address::zeroed()),
Identity::Address(Address::zeroed()),
)
.await
.unwrap();

let logs = response.decode_logs();
let open_trove_event = logs
.results
.iter()
.find(|log| log.as_ref().unwrap().contains("OpenTroveEvent"))
.expect("OpenTroveEvent not found")
.as_ref()
.unwrap();

assert!(
open_trove_event.contains(&admin.address().hash().to_string()),
"OpenTroveEvent should contain user address"
);
assert!(
open_trove_event.contains(&deposit_amount.to_string()),
"OpenTroveEvent should contain collateral amount"
);
assert!(
open_trove_event.contains(&with_min_borrow_fee(borrow_amount).to_string()),
"OpenTroveEvent should contain debt amount"
);
assert!(
open_trove_event.contains(&contracts.asset_contracts[0].asset_id.to_string()),
"OpenTroveEvent should contain asset id"
);

// Test AdjustTroveEvent
let response = borrow_operations_abi::add_coll(
&contracts.borrow_operations,
&contracts.asset_contracts[0].oracle,
&contracts.asset_contracts[0].mock_pyth_oracle,
&contracts.asset_contracts[0].mock_redstone_oracle,
&contracts.asset_contracts[0].asset,
&contracts.usdf,
&contracts.sorted_troves,
&contracts.asset_contracts[0].trove_manager,
&contracts.active_pool,
additional_collateral,
Identity::Address(Address::zeroed()),
Identity::Address(Address::zeroed()),
)
.await
.unwrap();

let logs = response.decode_logs();
let adjust_event = logs
.results
.iter()
.find(|log| log.as_ref().unwrap().contains("AdjustTroveEvent"))
.expect("AdjustTroveEvent not found")
.as_ref()
.unwrap();
println!("adjust_event: {:?}", adjust_event);
assert!(
adjust_event.contains(&admin.address().hash().to_string()),
"AdjustTroveEvent should contain user address"
);
assert!(
adjust_event.contains(&additional_collateral.to_string()),
"AdjustTroveEvent should contain collateral change amount"
);
assert!(
adjust_event.contains("is_collateral_increase: true"),
"AdjustTroveEvent should indicate collateral increase"
);
assert!(
adjust_event.contains("is_debt_increase: false"),
"AdjustTroveEvent should indicate debt is not increased"
);
// assetid
assert!(
adjust_event.contains(&contracts.asset_contracts[0].asset_id.to_string()),
"AdjustTroveEvent should contain asset id"
);
// total debt
assert!(
adjust_event.contains(&with_min_borrow_fee(borrow_amount).to_string()),
"AdjustTroveEvent should contain total debt"
);
// total coll
assert!(
adjust_event.contains(&(deposit_amount + additional_collateral).to_string()),
"AdjustTroveEvent should contain total collateral"
);

// create one more trove to allow for closing

let second_wallet = wallets[1].clone();

token_abi::mint_to_id(
&contracts.asset_contracts[0].asset,
5000 * PRECISION,
Identity::Address(second_wallet.address().into()),
)
.await;

let borrow_operations_second_wallet = BorrowOperations::new(
contracts.borrow_operations.contract_id().clone(),
second_wallet.clone(),
);

borrow_operations_abi::open_trove(
&borrow_operations_second_wallet,
&contracts.asset_contracts[0].oracle,
&contracts.asset_contracts[0].mock_pyth_oracle,
&contracts.asset_contracts[0].mock_redstone_oracle,
&contracts.asset_contracts[0].asset,
&contracts.usdf,
&contracts.fpt_staking,
&contracts.sorted_troves,
&contracts.asset_contracts[0].trove_manager,
&contracts.active_pool,
deposit_amount,
borrow_amount,
Identity::Address(Address::zeroed()),
Identity::Address(Address::zeroed()),
)
.await
.unwrap();

second_wallet
.transfer(
&admin.address(),
borrow_amount,
contracts.usdf_asset_id,
TxPolicies::default(),
)
.await
.unwrap();

// Test CloseTroveEvent
let response = borrow_operations_abi::close_trove(
&contracts.borrow_operations,
&contracts.asset_contracts[0].oracle,
&contracts.asset_contracts[0].mock_pyth_oracle,
&contracts.asset_contracts[0].mock_redstone_oracle,
&contracts.asset_contracts[0].asset,
&contracts.usdf,
&contracts.fpt_staking,
&contracts.sorted_troves,
&contracts.asset_contracts[0].trove_manager,
&contracts.active_pool,
with_min_borrow_fee(borrow_amount),
)
.await
.unwrap();

let logs = response.decode_logs();
let close_event = logs
.results
.iter()
.find(|log| log.as_ref().unwrap().contains("CloseTroveEvent"))
.expect("CloseTroveEvent not found")
.as_ref()
.unwrap();

assert!(
close_event.contains(&admin.address().hash().to_string()),
"CloseTroveEvent should contain user address"
);
assert!(
close_event.contains(&contracts.asset_contracts[0].asset_id.to_string()),
"CloseTroveEvent should contain asset id"
);
assert!(
close_event.contains(&(deposit_amount + additional_collateral).to_string()),
"CloseTroveEvent should contain collateral amount"
);
assert!(
close_event.contains(&with_min_borrow_fee(borrow_amount).to_string()),
"CloseTroveEvent should contain debt amount"
);
}
Loading
Loading