diff --git a/examples/wrapper/get-complete-fee-info.ts b/examples/wrapper/get-complete-fee-info.ts new file mode 100644 index 00000000..902b0f20 --- /dev/null +++ b/examples/wrapper/get-complete-fee-info.ts @@ -0,0 +1,42 @@ +import { getWrapperBags } from "./utils/getWrapperBags"; +import { processFeesBag } from "./utils/processFeeBag"; +import { processHistoricalFeeBag } from "./utils/processHistoricalFeeBag"; +import { printFeeSummary } from "./utils/printFeeSummary"; + +// yarn ts-node examples/wrapper/get-complete-fee-info.ts > complete-fee-info.log 2>&1 +(async () => { + const { deepReservesBagId, protocolFeesBagId, historicalCoverageFeesBagId, historicalProtocolFeesBagId } = + await getWrapperBags(); + + console.log("=== CURRENT FEES ==="); + + // Process current fee types + const deepReservesFees = await processFeesBag(deepReservesBagId); + const protocolFees = await processFeesBag(protocolFeesBagId); + + // Print current fees summaries + printFeeSummary( + "Current Deep Reserves Coverage Fees", + deepReservesFees.coinsMapByCoinType, + deepReservesFees.coinsMetadataMapByCoinType, + ); + printFeeSummary("Current Protocol Fees", protocolFees.coinsMapByCoinType, protocolFees.coinsMetadataMapByCoinType); + + console.log("\n=== HISTORICAL FEES ==="); + + // Process historical fee types + const historicalCoverageFees = await processHistoricalFeeBag(historicalCoverageFeesBagId); + const historicalProtocolFees = await processHistoricalFeeBag(historicalProtocolFeesBagId); + + // Print historical fees summaries + printFeeSummary( + "Historical Deep Reserves Coverage Fees", + historicalCoverageFees.coinsMapByCoinType, + historicalCoverageFees.coinsMetadataMapByCoinType, + ); + printFeeSummary( + "Historical Protocol Fees", + historicalProtocolFees.coinsMapByCoinType, + historicalProtocolFees.coinsMetadataMapByCoinType, + ); +})(); diff --git a/examples/wrapper/get-historical-fee-info.ts b/examples/wrapper/get-historical-fee-info.ts new file mode 100644 index 00000000..9d97cd82 --- /dev/null +++ b/examples/wrapper/get-historical-fee-info.ts @@ -0,0 +1,24 @@ +import { getWrapperBags } from "./utils/getWrapperBags"; +import { processHistoricalFeeBag } from "./utils/processHistoricalFeeBag"; +import { printFeeSummary } from "./utils/printFeeSummary"; + +// yarn ts-node examples/wrapper/get-historical-fee-info.ts > historical-fee-info.log 2>&1 +(async () => { + const { historicalCoverageFeesBagId, historicalProtocolFeesBagId } = await getWrapperBags(); + + // Process both historical fee types + const historicalCoverageFees = await processHistoricalFeeBag(historicalCoverageFeesBagId); + const historicalProtocolFees = await processHistoricalFeeBag(historicalProtocolFeesBagId); + + // Print summaries + printFeeSummary( + "Historical Deep Reserves Coverage Fees", + historicalCoverageFees.coinsMapByCoinType, + historicalCoverageFees.coinsMetadataMapByCoinType, + ); + printFeeSummary( + "Historical Protocol Fees", + historicalProtocolFees.coinsMapByCoinType, + historicalProtocolFees.coinsMetadataMapByCoinType, + ); +})(); diff --git a/examples/wrapper/utils/getWrapperBags.ts b/examples/wrapper/utils/getWrapperBags.ts index 50592010..8ddbb3ae 100644 --- a/examples/wrapper/utils/getWrapperBags.ts +++ b/examples/wrapper/utils/getWrapperBags.ts @@ -2,7 +2,7 @@ import { provider } from "../../common"; import { WRAPPER_OBJECT_ID } from "../../constants"; export async function getWrapperBags() { - // Fetch the wrapper object using its ID + // Fetch the wrapper object using its ID const wrapperObjectResponse = await provider.getObject({ id: WRAPPER_OBJECT_ID, options: { showContent: true }, @@ -15,10 +15,14 @@ export async function getWrapperBags() { const wrapperObject = wrapperObjectResponse.data.content.fields; - // Get the bag IDs for both fee types + // Get the bag IDs for current fees const deepReservesBagId = (wrapperObject as any).deep_reserves_coverage_fees?.fields?.id?.id; const protocolFeesBagId = (wrapperObject as any).protocol_fees?.fields?.id?.id; + // Get the bag IDs for historical fees + const historicalCoverageFeesBagId = (wrapperObject as any).historical_coverage_fees?.fields?.id?.id; + const historicalProtocolFeesBagId = (wrapperObject as any).historical_protocol_fees?.fields?.id?.id; + if (!deepReservesBagId) { throw new Error("Could not find deep_reserves_coverage_fees bag ID"); } @@ -27,5 +31,18 @@ export async function getWrapperBags() { throw new Error("Could not find protocol_fees bag ID"); } - return { deepReservesBagId, protocolFeesBagId }; -} \ No newline at end of file + if (!historicalCoverageFeesBagId) { + throw new Error("Could not find historical_coverage_fees bag ID"); + } + + if (!historicalProtocolFeesBagId) { + throw new Error("Could not find historical_protocol_fees bag ID"); + } + + return { + deepReservesBagId, + protocolFeesBagId, + historicalCoverageFeesBagId, + historicalProtocolFeesBagId, + }; +} diff --git a/examples/wrapper/utils/processHistoricalFeeBag.ts b/examples/wrapper/utils/processHistoricalFeeBag.ts new file mode 100644 index 00000000..b32a110b --- /dev/null +++ b/examples/wrapper/utils/processHistoricalFeeBag.ts @@ -0,0 +1,56 @@ +import { CoinsMapByCoinType, CoinsMetadataMapByCoinType } from "./types"; +import { provider } from "../../common"; +import { getCoinMetadata } from "./getCoinMetadata"; + +// Process historical fees from a specific bag (stored as u256 values) +export async function processHistoricalFeeBag(bagId: string): Promise<{ + coinsMapByCoinType: CoinsMapByCoinType; + coinsMetadataMapByCoinType: CoinsMetadataMapByCoinType; +}> { + const coinsMapByCoinType: CoinsMapByCoinType = {}; + const coinsMetadataMapByCoinType: CoinsMetadataMapByCoinType = {}; + + // Fetch all dynamic fields in the bag + const dynamicFields = await provider.getDynamicFields({ parentId: bagId }); + + // Fetch each field's content + for (const field of dynamicFields.data) { + const fieldObject = await provider.getDynamicFieldObject({ + parentId: bagId, + name: field.name, + }); + + // Extract coin type and historical amount information + if (fieldObject.data?.content?.dataType === "moveObject") { + const fieldName = field.name; + const fieldValue = fieldObject.data.content.fields; + + // The field name should contain the coin type information + // Historical fees are stored as ChargedFeeKey -> u256 + if (fieldName && typeof fieldName === "object" && "type" in fieldName) { + const nameType = (fieldName as any).type; + + // Extract coin type from the ChargedFeeKey type + if (nameType.includes("ChargedFeeKey<")) { + const coinType = nameType.substring( + nameType.indexOf("ChargedFeeKey<") + "ChargedFeeKey<".length, + nameType.length - 1, + ); + + // The historical amount is stored directly as u256 in the field value + const historicalAmount = (fieldValue as any).value || fieldValue; + + // Add to summary + coinsMapByCoinType[coinType] = BigInt(historicalAmount); + + // Fetch coin metadata if we haven't already + if (!coinsMetadataMapByCoinType[coinType]) { + coinsMetadataMapByCoinType[coinType] = await getCoinMetadata(coinType); + } + } + } + } + } + + return { coinsMapByCoinType, coinsMetadataMapByCoinType }; +} diff --git a/packages/deepbook-wrapper/sources/wrapper.move b/packages/deepbook-wrapper/sources/wrapper.move index fe885a2a..23145332 100644 --- a/packages/deepbook-wrapper/sources/wrapper.move +++ b/packages/deepbook-wrapper/sources/wrapper.move @@ -24,6 +24,8 @@ public struct Wrapper has key, store { deep_reserves: Balance, deep_reserves_coverage_fees: Bag, protocol_fees: Bag, + historical_coverage_fees: Bag, + historical_protocol_fees: Bag, } /// Capability for managing funds in the wrapper @@ -108,34 +110,56 @@ public(package) fun join_deep_reserves_coverage_fee( wrapper: &mut Wrapper, fee: Balance, ) { - if (fee.value() == 0) { + let fee_amount = fee.value(); + if (fee_amount == 0) { fee.destroy_zero(); return }; let key = ChargedFeeKey { dummy_field: false }; + + // Update current fees if (wrapper.deep_reserves_coverage_fees.contains(key)) { let balance = wrapper.deep_reserves_coverage_fees.borrow_mut(key); balance::join(balance, fee); } else { wrapper.deep_reserves_coverage_fees.add(key, fee); }; + + // Update historical total + if (wrapper.historical_coverage_fees.contains(key)) { + let current_total = wrapper.historical_coverage_fees.borrow_mut(key); + *current_total = *current_total + (fee_amount as u256); + } else { + wrapper.historical_coverage_fees.add(key, fee_amount as u256); + }; } /// Add collected protocol fees to the wrapper's fee storage public(package) fun join_protocol_fee(wrapper: &mut Wrapper, fee: Balance) { - if (fee.value() == 0) { + let fee_amount = fee.value(); + if (fee_amount == 0) { fee.destroy_zero(); return }; let key = ChargedFeeKey { dummy_field: false }; + + // Update current fees if (wrapper.protocol_fees.contains(key)) { let balance = wrapper.protocol_fees.borrow_mut(key); balance::join(balance, fee); } else { wrapper.protocol_fees.add(key, fee); }; + + // Update historical total + if (wrapper.historical_protocol_fees.contains(key)) { + let current_total = wrapper.historical_protocol_fees.borrow_mut(key); + *current_total = *current_total + (fee_amount as u256); + } else { + wrapper.historical_protocol_fees.add(key, fee_amount as u256); + }; } /// Get the splitted DEEP coin from the reserves @@ -158,6 +182,8 @@ fun init(ctx: &mut TxContext) { deep_reserves: balance::zero(), deep_reserves_coverage_fees: bag::new(ctx), protocol_fees: bag::new(ctx), + historical_coverage_fees: bag::new(ctx), + historical_protocol_fees: bag::new(ctx), }; // Create a fund capability for the deployer