From 925dd45a9662bf6f4a78ef825815abc36c28e4f5 Mon Sep 17 00:00:00 2001 From: Shrom Date: Thu, 9 Apr 2026 22:55:12 +0530 Subject: [PATCH 1/5] initial slush usdsui --- scripts/testRun.ts | 7 +- src/strategies/slushSingleAssetLooping.ts | 178 ++++++++++++++++++++++ 2 files changed, 182 insertions(+), 3 deletions(-) diff --git a/scripts/testRun.ts b/scripts/testRun.ts index 685d3e0..f2d1c59 100644 --- a/scripts/testRun.ts +++ b/scripts/testRun.ts @@ -63,7 +63,8 @@ export async function dryRunTransactionBlock(txb: Transaction, add?: string) { transactionBlock: serializedTxb, }) .then((res) => { - console.log(JSON.stringify(res, null, 2)); + // console.log(JSON.stringify(res, null, 2)); + console.log(res.effects.status, res.balanceChanges); }) .catch((error) => { console.error(error); @@ -259,9 +260,9 @@ async function claimAirdrop() { // executeTransactionBlock(tx); } // claimAirdrop(); -// withdraw(); +withdraw(); // poolsData(); // portfolioData(); // claimSlushWithdraw(); -deposit(); +// deposit(); // cancelSlushWithdraw(); diff --git a/src/strategies/slushSingleAssetLooping.ts b/src/strategies/slushSingleAssetLooping.ts index 8d9b577..f9f80b9 100644 --- a/src/strategies/slushSingleAssetLooping.ts +++ b/src/strategies/slushSingleAssetLooping.ts @@ -12,6 +12,7 @@ import { AlphalendClient } from '@alphafi/alphalend-sdk'; import { ALPHALEND_LENDING_PROTOCOL_ID, CLOCK_PACKAGE_ID, + GLOBAL_CONFIGS, IMAGE_URLS, VERSIONS, } from '../utils/constants.js'; @@ -207,6 +208,15 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< investor: { id: this.getStringField(fields.investor, 'id'), marketId: this.getStringField(fields.investor, 'market_id'), + positionCap: { + clientAddress: this.getNestedField( + fields, + 'investor.alphalend_position_cap.client_address', + ), + id: this.getNestedField(fields, 'investor.alphalend_position_cap.id'), + imageUrl: this.getNestedField(fields, 'investor.alphalend_position_cap.image_url'), + positionId: this.getNestedField(fields, 'investor.alphalend_position_cap.position_id'), + }, }, }; }, 'Failed to parse SlushSingleAssetLooping pool object'); @@ -285,6 +295,8 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< const alphalendClient = new AlphalendClient('mainnet', this.context.blockchain.suiClient); await alphalendClient.updatePrices(tx, [this.poolLabel.asset.type]); + await this.collectAndSwapRewards(tx); + // Get coin object const depositCoin = await this.context.blockchain.getCoinObject( tx, @@ -335,6 +347,8 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< const alphalendClient = new AlphalendClient('mainnet', this.context.blockchain.suiClient); await alphalendClient.updatePrices(tx, [this.poolLabel.asset.type]); + await this.collectAndSwapRewards(tx); + let xTokenAmount = this.coinAmountToXToken(options.amount); if (options.withdrawMax) { xTokenAmount = this.receiptObjects[0].xTokens; @@ -407,6 +421,164 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< async claimRewards(_tx: Transaction, _alphaReceipt: TransactionResult) { return; } + + /** + * Collect rewards from the position and swap them to the base asset + * Follows the same pattern as SingleAssetLooping strategy + */ + private async collectAndSwapRewards(tx: Transaction) { + const [ + alphaCoin, + stsuiCoin, + suiCoin, + blueCoin, + deepCoin, + usdcCoin, + walCoin, + tbtcCoin, + suibtcCoin, + xaumCoin, + ] = await this.context.getCoinsBySymbols([ + 'ALPHA', + 'stSUI', + 'SUI', + 'BLUE', + 'DEEP', + 'USDC', + 'WAL', + 'tBTC', + 'wBTC', + 'XAUm', + ]); + + let coinTypes = [ + alphaCoin, + stsuiCoin, + suiCoin, + blueCoin, + deepCoin, + usdcCoin, + walCoin, + tbtcCoin, + suibtcCoin, + xaumCoin, + ].map((entry) => entry.coinType); + + const alphalendClient = new AlphalendClient( + this.context.blockchain.network, + this.context.blockchain.suiClient, + ); + + // Get position ID from the pool object (investor is embedded) + const positionId = this.poolObject.investor.positionCap.positionId; + + let portfolio = await alphalendClient.getUserPortfolioFromPosition(positionId); + let rewards = portfolio?.rewardsToClaim; + + if (!rewards) { + console.log('no rewards for pool id: ', this.poolLabel.poolId); + return; + } + + // Loop through rewards and collect/swap each one + for (const x of rewards) { + if (x.coinType == alphaCoin.coinType) { + // ALPHA -> stSUI -> SUI + tx.moveCall({ + target: `${this.poolLabel.packageId}::alphalend_slush_locked_loop_pool::collect_reward_and_swap_bluefin`, + typeArguments: [this.poolLabel.asset.type, alphaCoin.coinType, stsuiCoin.coinType], + arguments: [ + tx.object(VERSIONS.SLUSH), + tx.object(this.poolLabel.poolId), + tx.object(this.poolObject.investor.id), + tx.object(ALPHALEND_LENDING_PROTOCOL_ID), + tx.object( + await this.context.getPoolIdBySymbolsAndProtocol('ALPHA', 'stSUI', 'bluefin'), + ), + tx.object(GLOBAL_CONFIGS.BLUEFIN), + tx.pure.bool(true), + tx.pure.bool(false), + tx.object(CLOCK_PACKAGE_ID), + ], + }); + tx.moveCall({ + target: `${this.poolLabel.packageId}::alphalend_slush_locked_loop_pool::collect_reward_and_swap_bluefin`, + typeArguments: [this.poolLabel.asset.type, stsuiCoin.coinType, suiCoin.coinType], + arguments: [ + tx.object(VERSIONS.SLUSH), + tx.object(this.poolLabel.poolId), + tx.object(this.poolObject.investor.id), + tx.object(ALPHALEND_LENDING_PROTOCOL_ID), + tx.object(await this.context.getPoolIdBySymbolsAndProtocol('stSUI', 'SUI', 'bluefin')), + tx.object(GLOBAL_CONFIGS.BLUEFIN), + tx.pure.bool(true), + tx.pure.bool(true), + tx.object(CLOCK_PACKAGE_ID), + ], + }); + } else if (coinTypes.includes(x.coinType) && x.coinType != this.poolLabel.asset.type) { + // Other rewards -> SUI + tx.moveCall({ + target: `${this.poolLabel.packageId}::alphalend_slush_locked_loop_pool::collect_reward_and_swap_bluefin`, + typeArguments: [this.poolLabel.asset.type, x.coinType, suiCoin.coinType], + arguments: [ + tx.object(VERSIONS.SLUSH), + tx.object(this.poolLabel.poolId), + tx.object(this.poolObject.investor.id), + tx.object(ALPHALEND_LENDING_PROTOCOL_ID), + tx.object( + await this.context.getPoolIdByTypesAndProtocol( + x.coinType, + suiCoin.coinType, + 'bluefin', + ), + ), + tx.object(GLOBAL_CONFIGS.BLUEFIN), + tx.pure.bool(true), + tx.pure.bool(true), + tx.object(CLOCK_PACKAGE_ID), + ], + }); + } + } + + // After collecting all rewards, handle base asset conversion + // If pool asset is USDSUI, convert SUI -> USDC, then USDC -> USDSUI + if (this.poolLabel.asset.name === 'USDSUI') { + // SUI -> USDC + tx.moveCall({ + target: `${this.poolLabel.packageId}::alphalend_slush_locked_loop_pool::collect_reward_and_swap_bluefin`, + typeArguments: [this.poolLabel.asset.type, suiCoin.coinType, usdcCoin.coinType], + arguments: [ + tx.object(VERSIONS.SLUSH), + tx.object(this.poolLabel.poolId), + tx.object(this.poolObject.investor.id), + tx.object(ALPHALEND_LENDING_PROTOCOL_ID), + tx.object(await this.context.getPoolIdBySymbolsAndProtocol('SUI', 'USDC', 'bluefin')), + tx.object(GLOBAL_CONFIGS.BLUEFIN), + tx.pure.bool(true), + tx.pure.bool(true), + tx.object(CLOCK_PACKAGE_ID), + ], + }); + // USDC -> USDSUI (base asset) + tx.moveCall({ + target: `${this.poolLabel.packageId}::alphalend_slush_locked_loop_pool::collect_reward_and_swap_bluefin`, + typeArguments: [this.poolLabel.asset.type, this.poolLabel.asset.type, usdcCoin.coinType], + arguments: [ + tx.object(VERSIONS.SLUSH), + tx.object(this.poolLabel.poolId), + tx.object(this.poolObject.investor.id), + tx.object(ALPHALEND_LENDING_PROTOCOL_ID), + tx.object(await this.context.getPoolIdBySymbolsAndProtocol('USDC', 'USDSUI', 'bluefin')), + tx.object(GLOBAL_CONFIGS.BLUEFIN), + tx.pure.bool(false), + tx.pure.bool(true), + tx.object(CLOCK_PACKAGE_ID), + ], + }); + } + } } /** @@ -421,6 +593,12 @@ export interface SlushSingleAssetLoopingPoolObject { investor: { id: string; marketId: string; + positionCap: { + clientAddress: string; + id: string; + imageUrl: string; + positionId: string; + }; }; } From 97ca9bdbf0a13810947c06c1870bd928fa4ba461 Mon Sep 17 00:00:00 2001 From: Shrom Date: Sun, 12 Apr 2026 00:28:26 +0530 Subject: [PATCH 2/5] usdsui single asset loop --- scripts/testRun.ts | 8 ++++---- src/strategies/slushSingleAssetLooping.ts | 10 +++++----- src/utils/testing-pools.ts | 13 ++++++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/scripts/testRun.ts b/scripts/testRun.ts index 902b908..7be43e6 100644 --- a/scripts/testRun.ts +++ b/scripts/testRun.ts @@ -199,13 +199,13 @@ async function deposit() { network: 'mainnet', }); const tx = await sdk.deposit({ - poolId: '0xccc08b2e42a88002b4bd505e7e0b5bed17079d4cafc2ccbe82da0172d5291867', + poolId: '0x0e1399fe66eca3147766bb113ae7b52b31243874c9e4a64a48e6d8cb91aa3c04', amount: 10_000n, address: address, isAmountA: false, }); - // dryRunTransactionBlock(tx); - executeTransactionBlock(tx); + dryRunTransactionBlock(tx); + // executeTransactionBlock(tx); } async function withdraw() { @@ -217,7 +217,7 @@ async function withdraw() { network: 'mainnet', }); const tx = await sdk.withdraw({ - poolId: '0xccc08b2e42a88002b4bd505e7e0b5bed17079d4cafc2ccbe82da0172d5291867', + poolId: '0x0bca47c53d57d203d19611af98a4e723c52cbf1bc58312360bfb5dcba0286de9', withdrawMax: true, amount: '5_000_000', isAmountA: true, diff --git a/src/strategies/slushSingleAssetLooping.ts b/src/strategies/slushSingleAssetLooping.ts index f9f80b9..221482e 100644 --- a/src/strategies/slushSingleAssetLooping.ts +++ b/src/strategies/slushSingleAssetLooping.ts @@ -490,7 +490,6 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< arguments: [ tx.object(VERSIONS.SLUSH), tx.object(this.poolLabel.poolId), - tx.object(this.poolObject.investor.id), tx.object(ALPHALEND_LENDING_PROTOCOL_ID), tx.object( await this.context.getPoolIdBySymbolsAndProtocol('ALPHA', 'stSUI', 'bluefin'), @@ -498,6 +497,7 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< tx.object(GLOBAL_CONFIGS.BLUEFIN), tx.pure.bool(true), tx.pure.bool(false), + tx.pure.u64(1000), tx.object(CLOCK_PACKAGE_ID), ], }); @@ -507,12 +507,12 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< arguments: [ tx.object(VERSIONS.SLUSH), tx.object(this.poolLabel.poolId), - tx.object(this.poolObject.investor.id), tx.object(ALPHALEND_LENDING_PROTOCOL_ID), tx.object(await this.context.getPoolIdBySymbolsAndProtocol('stSUI', 'SUI', 'bluefin')), tx.object(GLOBAL_CONFIGS.BLUEFIN), tx.pure.bool(true), tx.pure.bool(true), + tx.pure.u64(10), tx.object(CLOCK_PACKAGE_ID), ], }); @@ -524,7 +524,6 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< arguments: [ tx.object(VERSIONS.SLUSH), tx.object(this.poolLabel.poolId), - tx.object(this.poolObject.investor.id), tx.object(ALPHALEND_LENDING_PROTOCOL_ID), tx.object( await this.context.getPoolIdByTypesAndProtocol( @@ -536,6 +535,7 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< tx.object(GLOBAL_CONFIGS.BLUEFIN), tx.pure.bool(true), tx.pure.bool(true), + tx.pure.u64(10000), tx.object(CLOCK_PACKAGE_ID), ], }); @@ -552,12 +552,12 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< arguments: [ tx.object(VERSIONS.SLUSH), tx.object(this.poolLabel.poolId), - tx.object(this.poolObject.investor.id), tx.object(ALPHALEND_LENDING_PROTOCOL_ID), tx.object(await this.context.getPoolIdBySymbolsAndProtocol('SUI', 'USDC', 'bluefin')), tx.object(GLOBAL_CONFIGS.BLUEFIN), tx.pure.bool(true), tx.pure.bool(true), + tx.pure.u64(10000), tx.object(CLOCK_PACKAGE_ID), ], }); @@ -568,12 +568,12 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< arguments: [ tx.object(VERSIONS.SLUSH), tx.object(this.poolLabel.poolId), - tx.object(this.poolObject.investor.id), tx.object(ALPHALEND_LENDING_PROTOCOL_ID), tx.object(await this.context.getPoolIdBySymbolsAndProtocol('USDC', 'USDSUI', 'bluefin')), tx.object(GLOBAL_CONFIGS.BLUEFIN), tx.pure.bool(false), tx.pure.bool(true), + tx.pure.u64(10), tx.object(CLOCK_PACKAGE_ID), ], }); diff --git a/src/utils/testing-pools.ts b/src/utils/testing-pools.ts index 1c4c5bf..95fc5de 100644 --- a/src/utils/testing-pools.ts +++ b/src/utils/testing-pools.ts @@ -42,7 +42,7 @@ export const TEST_POOLS: PoolLabel[] = [ }, { poolId: '0x0bca47c53d57d203d19611af98a4e723c52cbf1bc58312360bfb5dcba0286de9', - packageId: '0x3221f39ee2ebdb94bff679589d836c9b4d6879194af745edf47f37c9d2c2e7c7', + packageId: '0xad19911966b8ba9d6c5240da9389ccf347059385a0e90fd19f9cce644560a989', strategyType: 'SlushSingleAssetLooping', parentProtocol: 'Alphalend', asset: { @@ -58,10 +58,9 @@ export const TEST_POOLS: PoolLabel[] = [ isNative: true, }, { - poolId: '0xccc08b2e42a88002b4bd505e7e0b5bed17079d4cafc2ccbe82da0172d5291867', - packageId: '0xf48bef4f768cb5dbd2c8993a1036a032a61ab526e5d0a940775611e8e24c09ca', - packageNumber: 12, - strategyType: 'SlushLending', + poolId: '0x0e1399fe66eca3147766bb113ae7b52b31243874c9e4a64a48e6d8cb91aa3c04', + packageId: '0xad19911966b8ba9d6c5240da9389ccf347059385a0e90fd19f9cce644560a989', + strategyType: 'SlushSingleAssetLooping', parentProtocol: 'Alphalend', asset: { name: 'USDSUI', @@ -69,10 +68,10 @@ export const TEST_POOLS: PoolLabel[] = [ }, events: { autocompoundEventType: - '0x41b1def47b6259cd7306e049d6500eabb1a984e25558b56eefa9b6c000a038c3::alphalend_slush_investor::AutoCompoundingEvent', + '0xad19911966b8ba9d6c5240da9389ccf347059385a0e90fd19f9cce644560a989::alphalend_slush_locked_loop_pool::XtokenRatioChangeEventV2', }, isActive: true, - poolName: 'ALPHALEND-SLUSH-LENDING-USDSUI', + poolName: 'ALPHALEND-SLUSH-USDSUI-SINGLE-LOOP', isNative: true, }, ]; From 6c0f72ef0931b90a428205e08a3737bc6d136b75 Mon Sep 17 00:00:00 2001 From: Shrom Date: Tue, 14 Apr 2026 00:25:46 +0530 Subject: [PATCH 3/5] testing package id --- src/utils/testing-pools.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/testing-pools.ts b/src/utils/testing-pools.ts index 95fc5de..9cdcb68 100644 --- a/src/utils/testing-pools.ts +++ b/src/utils/testing-pools.ts @@ -42,7 +42,7 @@ export const TEST_POOLS: PoolLabel[] = [ }, { poolId: '0x0bca47c53d57d203d19611af98a4e723c52cbf1bc58312360bfb5dcba0286de9', - packageId: '0xad19911966b8ba9d6c5240da9389ccf347059385a0e90fd19f9cce644560a989', + packageId: '0xcd3c28d6643fa2060d73d6e98bcc8049744b32804b017213a897e9466c5feb4d', strategyType: 'SlushSingleAssetLooping', parentProtocol: 'Alphalend', asset: { @@ -59,7 +59,7 @@ export const TEST_POOLS: PoolLabel[] = [ }, { poolId: '0x0e1399fe66eca3147766bb113ae7b52b31243874c9e4a64a48e6d8cb91aa3c04', - packageId: '0xad19911966b8ba9d6c5240da9389ccf347059385a0e90fd19f9cce644560a989', + packageId: '0xcd3c28d6643fa2060d73d6e98bcc8049744b32804b017213a897e9466c5feb4d', strategyType: 'SlushSingleAssetLooping', parentProtocol: 'Alphalend', asset: { From 166b4014ecb4faee7d655d5d8fdfe8ca781a074b Mon Sep 17 00:00:00 2001 From: Shrom Date: Tue, 14 Apr 2026 19:55:07 +0530 Subject: [PATCH 4/5] changed let to const --- src/strategies/slushSingleAssetLooping.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strategies/slushSingleAssetLooping.ts b/src/strategies/slushSingleAssetLooping.ts index 221482e..b6ae6f3 100644 --- a/src/strategies/slushSingleAssetLooping.ts +++ b/src/strategies/slushSingleAssetLooping.ts @@ -374,6 +374,7 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< async claimWithdraw(tx: Transaction, withdrawRequestId: string, address: string) { const alphalendClient = new AlphalendClient('mainnet', this.context.blockchain.suiClient); await alphalendClient.updatePrices(tx, [this.poolLabel.asset.type]); + await this.collectAndSwapRewards(tx); const positionCaps = await this.context.getSlushPositionCaps(address); if (positionCaps.length === 0) { throw new Error('No position cap found for claim'); @@ -398,6 +399,7 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< async cancelWithdraw(tx: Transaction, withdrawRequestId: string, address: string) { const alphalendClient = new AlphalendClient('mainnet', this.context.blockchain.suiClient); await alphalendClient.updatePrices(tx, [this.poolLabel.asset.type]); + await this.collectAndSwapRewards(tx); const positionCaps = await this.context.getSlushPositionCaps(address); if (positionCaps.length === 0) { throw new Error('No position cap found for cancellation'); @@ -451,7 +453,7 @@ export class SlushSingleAssetLoopingStrategy extends BaseStrategy< 'XAUm', ]); - let coinTypes = [ + const coinTypes = [ alphaCoin, stsuiCoin, suiCoin, From a11191c67345be2e527629ead36f795ca3ee4794 Mon Sep 17 00:00:00 2001 From: Shrom Date: Tue, 14 Apr 2026 22:43:18 +0530 Subject: [PATCH 5/5] assigning correct field name for pool label --- src/models/strategyContext.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/models/strategyContext.ts b/src/models/strategyContext.ts index 9c7e4d7..a8ad759 100644 --- a/src/models/strategyContext.ts +++ b/src/models/strategyContext.ts @@ -264,12 +264,11 @@ export class StrategyContext { return { poolId: d.pool_id, packageId: d.package_id, - packageNumber: d.package_number, strategyType: strategyType, parentProtocol: d.parent_protocol, asset: d.asset, events: { - autocompoundEventType: d.events?.autocompound_event_type, + autocompoundEventType: d.events?.xtoken_ratio_change_event_type, }, isActive: d.is_active, poolName: d.pool_name,