Skip to content

release: 3.0.1 #106

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

Merged
merged 2 commits into from
Sep 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
File renamed without changes.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Test

on:
pull_request:
branches: [ main, dev ]
branches: [ main, dev, release ]

env:
CARGO_TERM_COLOR: always
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion contract/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sweat_jar"
version = "3.0.0"
version = "3.0.1"
authors = ["Sweat Economy"]
edition = "2021"

Expand Down
42 changes: 21 additions & 21 deletions contract/src/claim/api.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use near_sdk::{env, ext_contract, is_promise_success, json_types::U128, near_bindgen, AccountId, PromiseOrValue};
use sweat_jar_model::{
api::ClaimApi,
claimed_amount_view::ClaimedAmountView,
jar::{AggregatedTokenAmountView, JarIdView},
U32,
api::ClaimApi, claimed_amount_view::ClaimedAmountView, jar::AggregatedTokenAmountView, TokenAmount, JAR_BATCH_SIZE,
};

use crate::{
Expand All @@ -29,52 +26,55 @@ impl ClaimApi for Contract {
fn claim_total(&mut self, detailed: Option<bool>) -> PromiseOrValue<ClaimedAmountView> {
let account_id = env::predecessor_account_id();
self.migrate_account_jars_if_needed(account_id.clone());
let jar_ids = self.account_jars(&account_id).iter().map(|a| U32(a.id)).collect();
self.claim_jars_internal(account_id, jar_ids, detailed)
self.claim_jars_internal(account_id, detailed)
}
}

impl Contract {
fn claim_jars_internal(
&mut self,
account_id: AccountId,
jar_ids: Vec<JarIdView>,
detailed: Option<bool>,
) -> PromiseOrValue<ClaimedAmountView> {
let now = env::block_timestamp_ms();
let mut accumulator = ClaimedAmountView::new(detailed);

let unlocked_jars: Vec<Jar> = self
.account_jars(&account_id)
let account_jars = self.account_jars(&account_id);

let mut unlocked_jars: Vec<((TokenAmount, u64), &Jar)> = account_jars
.iter()
.filter(|jar| !jar.is_pending_withdraw && jar_ids.contains(&U32(jar.id)))
.cloned()
.filter(|jar| !jar.is_pending_withdraw)
.map(|jar| {
let product = self.get_product(&jar.product_id);
(jar.get_interest(&product, now), jar)
})
.collect();

let mut event_data: Vec<ClaimEventItem> = vec![];
unlocked_jars.sort_by(|a, b| b.0 .0.cmp(&a.0 .0));

for jar in &unlocked_jars {
let product = self.get_product(&jar.product_id);
let (available_interest, remainder) = jar.get_interest(&product, now);
let jars_to_claim: Vec<_> = unlocked_jars.into_iter().take(JAR_BATCH_SIZE).collect();

let mut event_data: Vec<ClaimEventItem> = vec![];

if available_interest > 0 {
for ((available_interest, remainder), jar) in &jars_to_claim {
if *available_interest > 0 {
let jar = self.get_jar_mut_internal(&jar.account_id, jar.id);

jar.claim_remainder = remainder;
jar.claim_remainder = *remainder;

jar.claim(available_interest, available_interest, now).lock();
jar.claim(*available_interest, *available_interest, now).lock();

accumulator.add(jar.id, available_interest);
accumulator.add(jar.id, *available_interest);

event_data.push((jar.id, U128(available_interest)));
event_data.push((jar.id, U128(*available_interest)));
}
}

if accumulator.get_total().0 > 0 {
self.claim_interest(
&account_id,
accumulator,
unlocked_jars,
jars_to_claim.into_iter().map(|a| a.1).cloned().collect(),
EventKind::Claim(event_data),
now,
)
Expand Down
27 changes: 9 additions & 18 deletions contract/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,11 @@ struct SweatJarEvent {
/// `JarId` and interest to claim
pub type ClaimEventItem = (JarId, U128);

#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "near_sdk::serde")]
pub struct WithdrawData {
pub id: JarId,
pub fee: U128,
pub amount: U128,
}
/// (id, fee, amount)
pub type WithdrawData = (JarId, U128, U128);

/// (`old_id`, `new_id`)
pub type RestakeData = (JarId, JarId);

#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "near_sdk::serde")]
Expand All @@ -95,13 +93,6 @@ pub struct MigrationEventItem {
pub account_id: AccountId,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "near_sdk::serde")]
pub struct RestakeData {
pub old_id: JarId,
pub new_id: JarId,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "near_sdk::serde")]
pub struct PenaltyData {
Expand Down Expand Up @@ -189,7 +180,7 @@ mod test {
fn test_contract_version() {
let admin = admin();
let context = Context::new(admin);
assert_eq!(context.contract().contract_version(), "sweat_jar-3.0.0");
assert_eq!(context.contract().contract_version(), "sweat_jar-3.0.1");
}

#[test]
Expand All @@ -202,7 +193,7 @@ mod test {
.to_json_event_string(),
r#"EVENT_JSON:{
"standard": "sweat_jar",
"version": "3.0.0",
"version": "3.0.1",
"event": "top_up",
"data": {
"id": 10,
Expand Down Expand Up @@ -230,7 +221,7 @@ mod test {
.to_json_event_string(),
r#"EVENT_JSON:{
"standard": "sweat_jar",
"version": "3.0.0",
"version": "3.0.1",
"event": "create_jar",
"data": {
"id": 555,
Expand All @@ -250,7 +241,7 @@ mod test {
SweatJarEvent::from(EventKind::Claim(vec![(1, 1.into()), (2, 2.into())])).to_json_event_string(),
r#"EVENT_JSON:{
"standard": "sweat_jar",
"version": "3.0.0",
"version": "3.0.1",
"event": "claim",
"data": [
[
Expand Down
27 changes: 7 additions & 20 deletions contract/src/integration_test/integration_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(feature = "integration-test")]

use near_sdk::{env, near_bindgen, AccountId, Timestamp};
use sweat_jar_model::{api::IntegrationTestMethods, jar::JarView, ProductId};
use sweat_jar_model::{api::IntegrationTestMethods, ProductId};

use crate::{jar::model::Jar, Contract, ContractExt};

Expand All @@ -12,17 +12,11 @@ impl IntegrationTestMethods for Contract {
env::block_timestamp_ms()
}

fn bulk_create_jars(
&mut self,
account_id: AccountId,
product_id: ProductId,
principal: u128,
number_of_jars: u16,
) -> Vec<JarView> {
fn bulk_create_jars(&mut self, account_id: AccountId, product_id: ProductId, principal: u128, number_of_jars: u16) {
self.assert_manager();
let now = env::block_timestamp_ms();
(0..number_of_jars)
.map(|_| self.create_jar_for_integration_tests(&account_id, &product_id, principal))
.collect()
.for_each(|_| self.create_jar_for_integration_tests(&account_id, &product_id, principal, now));
}
}

Expand All @@ -33,18 +27,11 @@ impl Contract {
account_id: &AccountId,
product_id: &ProductId,
amount: u128,
) -> JarView {
let product = self.get_product(&product_id);

product.assert_enabled();
product.assert_cap(amount);

now: u64,
) {
let id = self.increment_and_get_last_jar_id();
let now = env::block_timestamp_ms();
let jar = Jar::create(id, account_id.clone(), product_id.clone(), amount, now);

self.add_new_jar(account_id, jar.clone());

jar.into()
self.add_new_jar(account_id, jar);
}
}
20 changes: 14 additions & 6 deletions contract/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ impl Contract {
self.last_jar_id
}

pub(crate) fn get_product(&self, product_id: &ProductId) -> Product {
self.products
.get(product_id)
.unwrap_or_else(|| env::panic_str(&format!("Product '{product_id}' doesn't exist")))
}

pub(crate) fn account_jars(&self, account_id: &AccountId) -> Vec<Jar> {
// TODO: Remove after complete migration and return '&[Jar]`
if let Some(record) = self.account_jars_v1.get(account_id) {
Expand Down Expand Up @@ -72,6 +66,20 @@ impl Contract {
jars.last_id = jar.id;
jars.push(jar);
}

// UnorderedMap doesn't have cache and deserializes `Product` on each get
// This cached getter significantly reduces gas usage
pub fn get_product(&self, product_id: &ProductId) -> Product {
self.products_cache
.borrow_mut()
.entry(product_id.clone())
.or_insert_with(|| {
self.products
.get(product_id)
.unwrap_or_else(|| env::panic_str(&format!("Product '{product_id}' doesn't exist")))
})
.clone()
}
}

pub(crate) fn assert_gas<Message: Display>(gas_needed: u64, error: impl FnOnce() -> Message) {
Expand Down
29 changes: 16 additions & 13 deletions contract/src/jar/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use near_sdk::{env, env::panic_str, json_types::U128, near_bindgen, require, Acc
use sweat_jar_model::{
api::JarApi,
jar::{AggregatedInterestView, AggregatedTokenAmountView, JarId, JarIdView, JarView},
TokenAmount, U32,
TokenAmount, JAR_BATCH_SIZE, U32,
};

use crate::{
event::{emit, EventKind, RestakeData},
event::{emit, EventKind},
jar::model::Jar,
Contract, ContractExt, JarsStorage,
};
Expand Down Expand Up @@ -128,7 +128,9 @@ impl JarApi for Contract {
let mut total_amount: TokenAmount = 0;

for jar in self.account_jars_with_ids(&account_id, &jar_ids) {
let interest = jar.get_interest(&self.get_product(&jar.product_id), now).0;
let product = self.get_product(&jar.product_id);

let interest = jar.get_interest(&product, now).0;

detailed_amounts.insert(U32(jar.id), U128(interest));
total_amount += interest;
Expand All @@ -147,22 +149,21 @@ impl JarApi for Contract {
self.migrate_account_jars_if_needed(env::predecessor_account_id());
let (old_id, jar) = self.restake_internal(jar_id);

emit(EventKind::Restake(RestakeData {
old_id,
new_id: jar.id.0,
}));
emit(EventKind::Restake((old_id, jar.id.0)));

jar
}

fn restake_all(&mut self) -> Vec<JarView> {
fn restake_all(&mut self, jars: Option<Vec<JarIdView>>) -> Vec<JarView> {
let account_id = env::predecessor_account_id();

self.migrate_account_jars_if_needed(account_id.clone());

let now = env::block_timestamp_ms();

let jars: Vec<Jar> = self
let jars_filter: Option<Vec<JarId>> = jars.map(|jars| jars.into_iter().map(|j| j.0).collect());

let mut jars: Vec<Jar> = self
.account_jars
.get(&account_id)
.unwrap_or_else(|| {
Expand All @@ -171,19 +172,21 @@ impl JarApi for Contract {
.jars
.iter()
.filter(|j| self.can_be_restaked(j, now))
.take(JAR_BATCH_SIZE)
.cloned()
.collect();

if let Some(jars_filter) = jars_filter {
jars.retain(|jar| jars_filter.contains(&jar.id));
}

let mut result = vec![];

let mut event_data = vec![];

for jar in &jars {
let (old_id, restaked) = self.restake_internal(jar.id.into());
event_data.push(RestakeData {
old_id,
new_id: restaked.id.0,
});
event_data.push((old_id, restaked.id.0));
result.push(restaked);
}

Expand Down
Loading