diff --git a/contracts/constants.tact b/contracts/constants.tact index 302f59f..dda02ed 100644 --- a/contracts/constants.tact +++ b/contracts/constants.tact @@ -5,6 +5,8 @@ const ACTION_LIQUIDATION: Int = 3; const RERUN_ACTION_UPDATE_POSITION: Int = 100; const RERUN_ACTION_MINT: Int = 101; +const RERUN_ACTION_TOKEN_TRANSFER: Int = 102; +const RERUN_ACTION_TOKEN_BURN: Int = 103; const JETTON_UNIT: Int = pow(10, 9); // Mock zero address diff --git a/contracts/jetton/assetToken/atoken-wallet.tact b/contracts/jetton/assetToken/atoken-wallet.tact index 3a19524..ff792a4 100644 --- a/contracts/jetton/assetToken/atoken-wallet.tact +++ b/contracts/jetton/assetToken/atoken-wallet.tact @@ -147,7 +147,7 @@ contract ATokenDefaultWallet queryId: msg.queryId, amount: msg.amount, owner: self.owner, - response_destination: self.owner + response_destination: msg.response_destination }.toCell() } ); diff --git a/contracts/jetton/assetToken/atoken.tact b/contracts/jetton/assetToken/atoken.tact index 950429a..67c57c7 100644 --- a/contracts/jetton/assetToken/atoken.tact +++ b/contracts/jetton/assetToken/atoken.tact @@ -28,7 +28,7 @@ contract AToken with ATokenJettonTrait { self.requireOwner(); self.requireNotStopped(); require(self.mintable, "Can't Mint Anymore"); - self.mint(msg.queryId, msg.receiver, msg.amount, self.owner); // (to, amount, response_destination) + self.mint(msg.queryId, msg.receiver, msg.amount, self.owner); // (queryId, to, amount, response_destination) } // ====== Get Methods ====== // diff --git a/contracts/jetton/debtToken/dtoken-master.tact b/contracts/jetton/debtToken/dtoken-master.tact index 1723433..4be029a 100644 --- a/contracts/jetton/debtToken/dtoken-master.tact +++ b/contracts/jetton/debtToken/dtoken-master.tact @@ -40,7 +40,7 @@ trait DTokenJettonTrait with Ownable, Deployable, Resumable { // @to The Address receive the Jetton token after minting // @amount The amount of Jetton token being minted // @response_destination The previous owner address - fun mint(to: Address, amount: Int, response_destination: Address) { + fun mint(queryId: Int, to: Address, amount: Int, response_destination: Address) { self.totalSupply = (self.totalSupply + amount); // Update total supply let winit: StateInit = self.getJettonWalletInit(to); // Create message @@ -50,7 +50,7 @@ trait DTokenJettonTrait with Ownable, Deployable, Resumable { bounce: false, mode: SendRemainingValue, body: TokenTransferInternal{ - queryId: 0, + queryId: queryId, amount: amount, from: myAddress(), response_destination: response_destination, diff --git a/contracts/jetton/debtToken/dtoken-wallet.tact b/contracts/jetton/debtToken/dtoken-wallet.tact index e0a2b85..1aa2439 100644 --- a/contracts/jetton/debtToken/dtoken-wallet.tact +++ b/contracts/jetton/debtToken/dtoken-wallet.tact @@ -92,7 +92,7 @@ contract DTokenDefaultWallet queryId: msg.queryId, amount: msg.amount, owner: self.owner, - response_destination: self.owner + response_destination: msg.response_destination }.toCell() } ); diff --git a/contracts/jetton/debtToken/dtoken.tact b/contracts/jetton/debtToken/dtoken.tact index d05e253..60a33e0 100644 --- a/contracts/jetton/debtToken/dtoken.tact +++ b/contracts/jetton/debtToken/dtoken.tact @@ -28,7 +28,7 @@ contract DToken with DTokenJettonTrait { self.requireOwner(); self.requireNotStopped(); require(self.mintable, "Can't Mint Anymore"); - self.mint(msg.receiver, msg.amount, self.owner); // (to, amount, response_destination) + self.mint(msg.queryId, msg.receiver, msg.amount, self.owner); // (queryId, to, amount, response_destination) } // ====== Get Methods ====== // diff --git a/contracts/jetton/messages.tact b/contracts/jetton/messages.tact index 6cb3475..5d01741 100644 --- a/contracts/jetton/messages.tact +++ b/contracts/jetton/messages.tact @@ -63,7 +63,6 @@ message CheckAndTransferAToken { // custom Mint message message Mint { queryId: Int as uint64; - token: Address; amount: Int; receiver: Address; } diff --git a/contracts/pool-view.tact b/contracts/pool-view.tact index 7cae40b..e510e45 100644 --- a/contracts/pool-view.tact +++ b/contracts/pool-view.tact @@ -26,8 +26,10 @@ trait PoolView with Ownable, Resumable { reservesConfiguration: map; reserveInterestRateStrategy: map; // bounce messages - updatePositionMsg: map; - mintMsg: map; + updatePositionMsg: map; + mintMsg: map; + tokenTransferMsg: map; + tokenBurnMsg: map; // ===== Get functions ===== @@ -101,20 +103,13 @@ trait PoolView with Ownable, Resumable { return self.reservesData.get(reserveAddress)!!; } - get fun reserveDataForUI(reserveAddress: Address): ReserveDataForUI { + get fun reserveDataAndConfiguration(reserveAddress: Address): ReserveDataAndConfiguration { let reserveData: ReserveData = self.reservesData.get(reserveAddress)!!; + let reserveConfiguration: ReserveConfiguration = self.reservesConfiguration.get(reserveAddress)!!; return - ReserveDataForUI{ - liquidityIndex: reserveData.liquidityIndex, - currentLiquidityRate: reserveData.currentLiquidityRate, - borrowIndex: reserveData.borrowIndex, - currentBorrowRate: reserveData.currentBorrowRate, - totalSupply: reserveData.totalSupply, - availableLiquidity: reserveData.availableLiquidity, - accruedToTreasury: reserveData.accruedToTreasury, - totalBorrow: reserveData.totalBorrow, - lastUpdateTimestamp: reserveData.lastUpdateTimestamp, - price: reserveData.price, + ReserveDataAndConfiguration{ + reserveData: reserveData, + reserveConfiguration: reserveConfiguration, normalizedIncome: reserveData.getNormalizedIncome(), normalizedDebt: reserveData.getNormalizedDebt() }; @@ -158,14 +153,22 @@ trait PoolView with Ownable, Resumable { } get fun bounceMsg(queryId: Int): Cell? { - let updatePositionMsg: UpdatePosition? = self.updatePositionMsg.get(queryId); + let updatePositionMsg: UpdatePositionBounce? = self.updatePositionMsg.get(queryId); if (updatePositionMsg != null) { return updatePositionMsg!!.toCell(); } - let mintMsg: Mint? = self.mintMsg.get(queryId); + let mintMsg: MintBounce? = self.mintMsg.get(queryId); if (mintMsg != null) { return mintMsg!!.toCell(); } + let tokenTransferMsg: TokenTransferBounce? = self.tokenTransferMsg.get(queryId); + if (tokenTransferMsg != null) { + return tokenTransferMsg!!.toCell(); + } + let tokenBurnMsg: TokenBurnBounce? = self.tokenBurnMsg.get(queryId); + if (tokenBurnMsg != null) { + return tokenBurnMsg!!.toCell(); + } return null; } } \ No newline at end of file diff --git a/contracts/pool.tact b/contracts/pool.tact index 75e4e64..b807fad 100644 --- a/contracts/pool.tact +++ b/contracts/pool.tact @@ -30,8 +30,10 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { reserveInterestRateStrategy: map; // bounce messages - updatePositionMsg: map; - mintMsg: map; + updatePositionMsg: map; + mintMsg: map; + tokenTransferMsg: map; + tokenBurnMsg: map; init() { self.owner = sender(); @@ -93,7 +95,7 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { let reserveAddress: Address = msg.tokenAddress; let reserveConfiguration: ReserveConfiguration? = self.reservesConfiguration.get(reserveAddress); require(reserveConfiguration != null, "Reserve not found"); - + // GetUserAccountData don't need do bounce send(SendParameters{ to: userAccountAddress, value: 0, @@ -116,6 +118,7 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { let reserveAddress: Address = msg.tokenAddress; let reserveConfiguration: ReserveConfiguration? = self.reservesConfiguration.get(reserveAddress); require(reserveConfiguration != null, "Reserve not found"); + // GetUserAccountData don't need do bounce send(SendParameters{ to: userAccountAddress, value: 0, @@ -160,9 +163,9 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { self.reservesData.set(reserveAddress, reserveData); // Transfer borrowAmount Token(tokenAddress) to the user. let poolWalletAddress: Address = reserveConfigration.poolWalletAddress; - self.sendTokenTransferByPool(msg.queryId, poolWalletAddress, msg.user, borrowAmount); + self.sendTokenTransferByPool(poolWalletAddress, msg.user, borrowAmount); // TODO: calculate fees and Ton to send - self.updateUserAccountPosition(msg.queryId, msg.user, msg.tokenAddress, 0, scaledBorrowAmount); + self.updateUserAccountPosition(msg.user, msg.tokenAddress, 0, scaledBorrowAmount); } if(msg.action == ACTION_WITHDRAW) { @@ -177,9 +180,9 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { self.reservesData.set(reserveAddress, reserveData); // Transfer withdrawAmount Token(tokenAddress) to the user. let poolWalletAddress: Address = reserveConfigration.poolWalletAddress; - self.sendTokenTransferByPool(msg.queryId, poolWalletAddress, msg.user, withdrawAmount); + self.sendTokenTransferByPool(poolWalletAddress, msg.user, withdrawAmount); // TODO: calculate fees and Ton to send - self.updateUserAccountPosition(msg.queryId, msg.user, msg.tokenAddress, -scaledWithdrawAmount, 0); + self.updateUserAccountPosition(msg.user, msg.tokenAddress, -scaledWithdrawAmount, 0); } } @@ -196,6 +199,8 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { // we can delete the key of the queryId from `mintMsg` map and `tokenTransferMsg` map in the same time, // And only one map will be updated. self.mintMsg.del(msg.queryId); + self.tokenTransferMsg.del(msg.queryId); + self.tokenBurnMsg.del(msg.queryId); } receive(msg: RerunBounceMsg) { @@ -205,23 +210,51 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { if (msg.action == RERUN_ACTION_MINT) { self.rerunMintMsg(msg.queryId); } + if (msg.action == RERUN_ACTION_TOKEN_TRANSFER) { + self.rerunSendTokenTransferByPool(msg.queryId); + } + if (msg.action == RERUN_ACTION_TOKEN_BURN) { + self.rerunTokenBurnMsg(msg.queryId); + } } - fun sendTokenTransferByPool(queryId: Int, poolWalletAddress: Address, toAddress: Address, amount: Int) { + fun sendTokenTransferByPool(poolWalletAddress: Address, toAddress: Address, amount: Int) { + let queryId: Int = self.queryId; + let tokenTransferMsg: TokenTransfer = TokenTransfer{ + queryId: queryId, + amount: amount, + destination: toAddress, + response_destination: myAddress(), // Pool need to receive TokenExcesses message + custom_payload: null, + forward_ton_amount: 0, + forward_payload: emptySlice() + }; + // store TokenTransferBounce + let bounceMsg: TokenTransferBounce = TokenTransferBounce{ + to: poolWalletAddress, + user: toAddress, + msg: tokenTransferMsg + }; + self.tokenTransferMsg.set(queryId, bounceMsg); + self.queryId += 1; + send(SendParameters{ to: poolWalletAddress, value: ton("0.05"), bounce: true, mode: SendPayGasSeparately, - body: TokenTransfer{ - queryId: queryId, - amount: amount, - destination: toAddress, - response_destination: toAddress, - custom_payload: null, - forward_ton_amount: 0, - forward_payload: emptySlice() - }.toCell() + body: tokenTransferMsg.toCell() + }); + } + + fun rerunSendTokenTransferByPool(queryId: Int) { + let bounce: TokenTransferBounce = self.tokenTransferMsg.get(queryId)!!; + send(SendParameters{ + to: bounce.to, + value: ton("0.05"), + bounce: true, + mode: SendPayGasSeparately, + body: bounce.msg.toCell() }); } @@ -281,11 +314,15 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { let queryId: Int = self.queryId; let mintMsg: Mint = Mint{ queryId: queryId, - token: aTokenAddress, amount: amount, receiver: user }; - self.mintMsg.set(queryId, mintMsg); + let bounce: MintBounce = MintBounce{ + to: aTokenAddress, + user: user, + msg: mintMsg + }; + self.mintMsg.set(queryId, bounce); self.queryId += 1; send(SendParameters{ @@ -298,61 +335,102 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { } fun burnAToken(asset: Address, user: Address, amount: Int) { + let queryId: Int = self.queryId; + let tokenBurnMsg: TokenBurn = TokenBurn{ + queryId: queryId, + amount: amount, + owner: user, + response_destination: myAddress() // Pool need to receive TokenExcesses message + }; + let to: Address = self.userATokenWalletAddress(asset, user); + let bounce: TokenBurnBounce = TokenBurnBounce{ + to: to, + user: user, + msg: tokenBurnMsg + }; + self.tokenBurnMsg.set(queryId, bounce); + self.queryId += 1; + send(SendParameters{ - to: self.userATokenWalletAddress(asset, user), + to: to, value: 0, bounce: true, mode: SendRemainingValue, - body: TokenBurn{ - queryId: self.queryId, - amount: amount, - owner: user, - response_destination: user // This field isn't used in TokenBurn - }.toCell() + body: tokenBurnMsg.toCell() }); } fun burnDToken(asset: Address, user: Address, amount: Int) { + let queryId: Int = self.queryId; + let tokenBurnMsg: TokenBurn = TokenBurn{ + queryId: queryId, + amount: amount, + owner: user, + response_destination: myAddress() // Pool need to receive TokenExcesses message + }; + let to: Address = self.userDTokenWalletAddress(asset, user); + let bounce: TokenBurnBounce = TokenBurnBounce{ + to: to, + user: user, + msg: tokenBurnMsg + }; + self.tokenBurnMsg.set(queryId, bounce); + self.queryId += 1; + send(SendParameters{ - to: self.userDTokenWalletAddress(asset, user), + to: to, value: 0, bounce: true, mode: SendRemainingValue, - body: TokenBurn{ - queryId: self.queryId, - amount: amount, - owner: user, - response_destination: user // This field isn't used in TokenBurn - }.toCell() + body: tokenBurnMsg.toCell() }); } - // TODO: handle bounce message fun mintDToken(asset: Address, user: Address, amount: Int) { let dTokenAddress: Address = self.reservesConfiguration.get(asset)!!.dTokenAddress; + // store mintMsg + let queryId: Int = self.queryId; + let mintMsg: Mint = Mint{ + queryId: queryId, + amount: amount, + receiver: user + }; + let bounce: MintBounce = MintBounce{ + to: dTokenAddress, + user: user, + msg: mintMsg + }; + self.mintMsg.set(queryId, bounce); + self.queryId += 1; + send(SendParameters{ to: dTokenAddress, value: 0, bounce: true, mode: SendRemainingValue, - body: Mint{ - queryId: self.queryId, - token: dTokenAddress, - amount: amount, - receiver: user - }.toCell() + body: mintMsg.toCell() }); - self.queryId += 1; } fun rerunMintMsg(queryId: Int) { - let msg: Mint = self.mintMsg.get(queryId)!!; + let bounce: MintBounce = self.mintMsg.get(queryId)!!; send(SendParameters{ - to: msg.token, + to: bounce.to, value: 0, bounce: true, mode: SendRemainingValue, - body: msg.toCell() + body: bounce.msg.toCell() + }); + } + + fun rerunTokenBurnMsg(queryId: Int) { + let bounce: TokenBurnBounce = self.tokenBurnMsg.get(queryId)!!; + send(SendParameters{ + to: bounce.to, + value: 0, + bounce: true, + mode: SendRemainingValue, + body: bounce.msg.toCell() }); } @@ -409,7 +487,7 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { reserveData.totalSupply += scaledSupplyAmount; self.reservesData.set(matchedReserve!!, reserveData); - self.updateUserAccountPosition(msg.queryId, msg.from, matchedReserve!!, scaledSupplyAmount, 0); + self.updateUserAccountPosition(msg.from, matchedReserve!!, scaledSupplyAmount, 0); } // use crc32 code of 'Repay': utils.calculateRequestOpcode_1('Repay') @@ -427,22 +505,27 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { reserveData.totalBorrow -= scaledBorrowAmount; self.reservesData.set(matchedReserve!!, reserveData); - self.updateUserAccountPosition(msg.queryId, msg.from, matchedReserve!!, 0, -scaledBorrowAmount); + self.updateUserAccountPosition(msg.from, matchedReserve!!, 0, -scaledBorrowAmount); } } - fun updateUserAccountPosition(queryId: Int, ownerAddress: Address, reserveAddress: Address, supply: Int, borrow: Int) { + fun updateUserAccountPosition(ownerAddress: Address, reserveAddress: Address, supply: Int, borrow: Int) { + let queryId: Int = self.queryId; let userAccountInit: StateInit = self.getUserAccountInit(ownerAddress); let userAccountAddress: Address = contractAddress(userAccountInit); - let msg: UpdatePosition = UpdatePosition{ queryId: queryId, - user: ownerAddress, address: reserveAddress, supply: supply, borrow: borrow }; - self.updatePositionMsg.set(queryId, msg); + let updatePositionBounce: UpdatePositionBounce = UpdatePositionBounce{ + to: userAccountAddress, + user: ownerAddress, + msg: msg + }; + + self.updatePositionMsg.set(queryId, updatePositionBounce); self.queryId += 1; send(SendParameters{ @@ -458,17 +541,17 @@ contract Pool with Deployable, Ownable, Resumable, PoolView { // rerun the stored UpdatePositionMsg which isn't deleted in the UserPositionUpdated. fun rerunUpdatePositionMsg(queryId: Int) { - let msg: UpdatePosition = self.updatePositionMsg.get(queryId)!!; + let bounce: UpdatePositionBounce = self.updatePositionMsg.get(queryId)!!; - let userAccountInit: StateInit = self.getUserAccountInit(msg.user); + let userAccountInit: StateInit = self.getUserAccountInit(bounce.user); let userAccountAddress: Address = contractAddress(userAccountInit); send(SendParameters{ - to: userAccountAddress, + to: bounce.to, value: 0, bounce: true, mode: SendRemainingValue, - body: msg.toCell(), + body: bounce.msg.toCell(), code: userAccountInit.code, data: userAccountInit.data }); diff --git a/contracts/types/message.tact b/contracts/types/message.tact index 3efc972..7ba0f18 100644 --- a/contracts/types/message.tact +++ b/contracts/types/message.tact @@ -1,4 +1,6 @@ import "./struct"; +import "../jetton/messages"; + // TODO: update the message id message(0x66660001) AddReserve { reserveAddress: Address; @@ -40,7 +42,6 @@ message(0x66660006) WithdrawToken { } message UpdatePosition { queryId: Int as uint64; - user: Address; address: Address; supply: Int as int128; borrow: Int as int128; @@ -61,3 +62,23 @@ message RerunBounceMsg { queryId: Int as uint64; action: Int as uint8; } +message UpdatePositionBounce { + to: Address; + user: Address; + msg: UpdatePosition; +} +message MintBounce { + to: Address; + user: Address; + msg: Mint; +} +message TokenTransferBounce { + to: Address; + user: Address; + msg: TokenTransfer; +} +message TokenBurnBounce { + to: Address; + user: Address; + msg: TokenBurn; +} diff --git a/contracts/types/struct.tact b/contracts/types/struct.tact index 8cdb89e..c0e2c6b 100644 --- a/contracts/types/struct.tact +++ b/contracts/types/struct.tact @@ -38,17 +38,9 @@ struct ReserveData { price: Int as uint64; } -struct ReserveDataForUI { - liquidityIndex: Int as uint128; - currentLiquidityRate: Int as uint128; - borrowIndex: Int as uint128; - currentBorrowRate: Int as uint128; - totalSupply: Int as coins; - availableLiquidity: Int as coins; - accruedToTreasury: Int as coins; - totalBorrow: Int as coins; - lastUpdateTimestamp: Int as uint32; - price: Int as uint64; +struct ReserveDataAndConfiguration { + reserveData: ReserveData; + reserveConfiguration: ReserveConfiguration; normalizedIncome: Int as uint128; normalizedDebt: Int as uint128; } diff --git a/helpers/constant.ts b/helpers/constant.ts index 8a551f7..ef82ce3 100644 --- a/helpers/constant.ts +++ b/helpers/constant.ts @@ -9,3 +9,5 @@ export const ACTION_LIQUIDATION = 3n; export const RERUN_ACTION_UPDATE_POSITION = 100n; export const RERUN_ACTION_MINT = 101n; +export const RERUN_ACTION_TOKEN_TRANSFER = 102n; +export const RERUN_ACTION_TOKEN_BURN = 103n; diff --git a/helpers/pool.ts b/helpers/pool.ts index a8651e9..1a73fb6 100644 --- a/helpers/pool.ts +++ b/helpers/pool.ts @@ -1,19 +1,39 @@ import { Cell } from '@ton/core'; -import { loadMint, loadUpdatePosition, Mint, UpdatePosition } from '../wrappers/Pool'; +import { + loadMintBounce, + loadTokenBurnBounce, + loadTokenTransferBounce, + loadUpdatePositionBounce, + MintBounce, + TokenBurnBounce, + TokenTransferBounce, + UpdatePositionBounce, +} from '../wrappers/Pool'; -export const parsePoolBounceMessage = (message: Cell | null): UpdatePosition | Mint | null => { +export const parsePoolBounceMessage = ( + message: Cell | null, +): UpdatePositionBounce | MintBounce | TokenTransferBounce | TokenBurnBounce | null => { if (message === null) return null; - const msgSlice = message.asSlice(); try { - const updatePositionMsg = loadUpdatePosition(msgSlice); + const updatePositionMsg = loadUpdatePositionBounce(message.asSlice()); return updatePositionMsg; } catch (error) {} try { - const mintMsg = loadMint(msgSlice); + const mintMsg = loadMintBounce(message.asSlice()); return mintMsg; } catch (error) {} + + try { + const tokenTransferMsg = loadTokenTransferBounce(message.asSlice()); + return tokenTransferMsg; + } catch (error) {} + + try { + const tokenBurnMsg = loadTokenBurnBounce(message.asSlice()); + return tokenBurnMsg; + } catch (error) {} console.log('Failed to parse bounce message'); return null; }; diff --git a/scripts/mintJetton.ts b/scripts/mintJetton.ts index 14819eb..c5dfa9e 100644 --- a/scripts/mintJetton.ts +++ b/scripts/mintJetton.ts @@ -27,7 +27,6 @@ export async function run(provider: NetworkProvider, args: string[]) { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, receiver: userAddress, amount: 1000000000000n, } diff --git a/tests/Pool.Borrow.spec.ts b/tests/Pool.Borrow.spec.ts index 8e8810b..5b5ea89 100644 --- a/tests/Pool.Borrow.spec.ts +++ b/tests/Pool.Borrow.spec.ts @@ -228,7 +228,6 @@ describe('Pool', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: toNano(100n), receiver: deployer.address, }, diff --git a/tests/Pool.Calculation.spec.ts b/tests/Pool.Calculation.spec.ts index bafac3a..80276e9 100644 --- a/tests/Pool.Calculation.spec.ts +++ b/tests/Pool.Calculation.spec.ts @@ -164,7 +164,6 @@ describe('Pool indexes calculation', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: toNano(10000n), receiver: deployer.address, }, @@ -178,7 +177,6 @@ describe('Pool indexes calculation', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: toNano(10000n), receiver: secondUser.address, }, @@ -353,7 +351,7 @@ describe('Pool indexes calculation', () => { const supplyAmount = toNano(100n); await supply(deployer.getSender(), supplyAmount); - let reserveData = await pool.getReserveDataForUi(sampleJetton.address); + let reserveData = (await pool.getReserveDataAndConfiguration(sampleJetton.address)).reserveData; // no debts, no rates expect(reserveData.liquidityIndex).toEqual(RAY); expect(reserveData.borrowIndex).toEqual(RAY); @@ -362,7 +360,7 @@ describe('Pool indexes calculation', () => { await sleep(5 * 1000); - reserveData = await pool.getReserveDataForUi(sampleJetton.address); + reserveData = (await pool.getReserveDataAndConfiguration(sampleJetton.address)).reserveData; // no debts, no rates expect(reserveData.liquidityIndex).toEqual(RAY); expect(reserveData.borrowIndex).toEqual(RAY); @@ -370,7 +368,7 @@ describe('Pool indexes calculation', () => { expect(reserveData.currentBorrowRate).toEqual(0n); await supply(secondUser.getSender(), supplyAmount); - reserveData = await pool.getReserveDataForUi(sampleJetton.address); + reserveData = (await pool.getReserveDataAndConfiguration(sampleJetton.address)).reserveData; // no debts, no rates expect(reserveData.liquidityIndex).toEqual(RAY); expect(reserveData.borrowIndex).toEqual(RAY); @@ -378,11 +376,12 @@ describe('Pool indexes calculation', () => { expect(reserveData.currentBorrowRate).toEqual(0n); await sleep(5 * 1000); - let reserveDataBefore = await pool.getReserveDataForUi(sampleJetton.address); + let reserveDataBefore = (await pool.getReserveDataAndConfiguration(sampleJetton.address)).reserveData; const borrowAmount = toNano(50n); await borrow(secondUser.getSender(), borrowAmount); await sleep(5 * 1000); - reserveData = await pool.getReserveDataForUi(sampleJetton.address); + const reserveDataAndConfiguration = await pool.getReserveDataAndConfiguration(sampleJetton.address); + reserveData = reserveDataAndConfiguration.reserveData // first borrow, the index still should be RAY, the rates should not be zero expect(reserveData.liquidityIndex).toEqual(RAY); expect(reserveData.borrowIndex).toEqual(RAY); @@ -407,24 +406,24 @@ describe('Pool indexes calculation', () => { // non-zero debts, non-zero rates // normalizedIncome is the real-time liquidityIndex // normalizedDebt is the real-time borrowIndex - expect(reserveData.normalizedIncome).toEqual( + expect(reserveDataAndConfiguration.normalizedIncome).toEqual( await mathUtils.getCalculateLinearInterest( reserveData.currentLiquidityRate, reserveData.lastUpdateTimestamp, ), ); - expect(reserveData.normalizedDebt).toEqual( + expect(reserveDataAndConfiguration.normalizedDebt).toEqual( await mathUtils.getCalculateCompoundedInterest( reserveData.currentBorrowRate, reserveData.lastUpdateTimestamp, ), ); - const normalizedIncomeBefore = reserveData.normalizedIncome; - const normalizedDebtBefore = reserveData.normalizedDebt; + const normalizedIncomeBefore = reserveDataAndConfiguration.normalizedIncome; + const normalizedDebtBefore = reserveDataAndConfiguration.normalizedDebt; reserveDataBefore = reserveData; await supply(deployer.getSender(), supplyAmount); await sleep(5 * 1000); - reserveData = await pool.getReserveDataForUi(sampleJetton.address); + reserveData = (await pool.getReserveDataAndConfiguration(sampleJetton.address)).reserveData; // after the first borrow, the other action will update the indexes. expect(reserveData.liquidityIndex).toEqual(normalizedIncomeBefore); expect(reserveData.borrowIndex).toEqual(normalizedDebtBefore); diff --git a/tests/Pool.Repay.spec.ts b/tests/Pool.Repay.spec.ts index eea9403..0c337b2 100644 --- a/tests/Pool.Repay.spec.ts +++ b/tests/Pool.Repay.spec.ts @@ -219,7 +219,6 @@ describe('Pool', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: toNano(100n), receiver: deployer.address, }, diff --git a/tests/Pool.Supply.spec.ts b/tests/Pool.Supply.spec.ts index c8e68ce..7ed23d0 100644 --- a/tests/Pool.Supply.spec.ts +++ b/tests/Pool.Supply.spec.ts @@ -6,6 +6,7 @@ import { ReserveConfiguration, ReserveInterestRateStrategy, UpdatePosition, + UpdatePositionBounce, } from '../wrappers/Pool'; import '@ton/test-utils'; import { SampleJetton } from '../build/SampleJetton/tact_SampleJetton'; @@ -156,7 +157,6 @@ describe('Pool Supply', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: 100000000000n, receiver: deployer.address, }, @@ -400,13 +400,13 @@ describe('Pool Supply', () => { expect(accountData.positionsLength).toEqual(0n); let msgId = (await pool.getQueryId()) - 1n; - const updatePositionMsg = parsePoolBounceMessage(await pool.getBounceMsg(msgId)) as UpdatePosition; - expect(updatePositionMsg?.$$type).toEqual('UpdatePosition'); - expect(updatePositionMsg?.queryId).toEqual(msgId); + const updatePositionMsg = parsePoolBounceMessage(await pool.getBounceMsg(msgId)) as UpdatePositionBounce; + expect(updatePositionMsg?.$$type).toEqual('UpdatePositionBounce'); + expect(updatePositionMsg?.msg.queryId).toEqual(msgId); expect(updatePositionMsg?.user.toString()).toEqual(deployer.getSender().address.toString()); - expect(updatePositionMsg?.address.toString()).toEqual(sampleJetton.address.toString()); - expect(updatePositionMsg?.supply).toEqual(100000000000n); - expect(updatePositionMsg?.borrow).toEqual(0n); + expect(updatePositionMsg?.msg.address.toString()).toEqual(sampleJetton.address.toString()); + expect(updatePositionMsg?.msg.supply).toEqual(100000000000n); + expect(updatePositionMsg?.msg.borrow).toEqual(0n); result = await pool.send( deployer.getSender(), diff --git a/tests/Pool.Withdraw.spec.ts b/tests/Pool.Withdraw.spec.ts index 67a670c..1af6444 100644 --- a/tests/Pool.Withdraw.spec.ts +++ b/tests/Pool.Withdraw.spec.ts @@ -1,6 +1,13 @@ import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox'; import { address, beginCell, Cell, fromNano, toNano } from '@ton/core'; -import { ATokenDTokenContents, Pool, ReserveConfiguration, ReserveInterestRateStrategy } from '../wrappers/Pool'; +import { + ATokenDTokenContents, + Pool, + ReserveConfiguration, + ReserveInterestRateStrategy, + TokenBurnBounce, + UpdatePositionBounce, +} from '../wrappers/Pool'; import '@ton/test-utils'; import { SampleJetton } from '../build/SampleJetton/tact_SampleJetton'; import { buildOnchainMetadata } from '../scripts/utils'; @@ -9,9 +16,10 @@ import { UserAccount } from '../build/Pool/tact_UserAccount'; import { DTokenDefaultWallet } from '../build/DToken/tact_DTokenDefaultWallet'; import { AToken } from '../wrappers/AToken'; import { DToken } from '../wrappers/DToken'; -import { PERCENTAGE_FACTOR } from '../helpers/constant'; +import { PERCENTAGE_FACTOR, RERUN_ACTION_TOKEN_BURN, RERUN_ACTION_UPDATE_POSITION } from '../helpers/constant'; import { ATokenDefaultWallet } from '../build/AToken/tact_ATokenDefaultWallet'; import { sleep } from '@ton/blueprint'; +import { parsePoolBounceMessage } from '../helpers/pool'; describe('Pool Withdraw', () => { let blockchain: Blockchain; @@ -295,7 +303,6 @@ describe('Pool Withdraw', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: 100000000000n, receiver: deployer.address, }, @@ -305,15 +312,329 @@ describe('Pool Withdraw', () => { await supplyFromDeployer(supplyAmount); }); - it('withdraw successfully with no debt', async () => { - const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); + // it('withdraw successfully with no debt', async () => { + // const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); + // const withdrawAmount = toNano(50n); + // const deployerJettonBalanceBefore = (await deployerJettonDefaultWallet.getGetWalletData()).balance; + + // const result = await pool.send( + // deployer.getSender(), + // { + // value: toNano('1.5'), + // }, + // { + // $$type: 'WithdrawToken', + // tokenAddress: sampleJetton.address, + // amount: withdrawAmount, + // }, + // ); + + // // WithdrawToken + // expect(result.transactions).toHaveTransaction({ + // from: deployer.address, + // to: pool.address, + // success: true, + // }); + + // // GetUserAccountData + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserAccountDataResponse + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: true, + // }); + + // // sendTokenTransferByPool TokenTransfer + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: poolWallet.address, + // success: true, + // }); + + // // UpdatePosition + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserPositionUpdated + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: true, + // }); + + // // Burn aToken + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: deployerATokenDefaultWallet.address, + // success: true, + // }); + + // // aToken-wallet to aToken-master TokenBurnNotification + // expect(result.transactions).toHaveTransaction({ + // from: deployerATokenDefaultWallet.address, + // to: aToken.address, + // success: true, + // }); + + // const userAccountContract = blockchain.openContract(userAccountAddress); + // const accountData = await userAccountContract.getAccount(); + // expect(accountData.positionsDetail?.get(sampleJetton.address)!!.supply).toEqual(supplyAmount - withdrawAmount); + // expect(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow).toEqual(toNano(0n)); + + // const walletData = await deployerATokenDefaultWallet.getGetWalletData(); + // expect(walletData.balance).toEqual(supplyAmount - withdrawAmount); + // expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( + // deployerJettonBalanceBefore + withdrawAmount, + // ); + // }); + + // it('withdraw max amount successfully with no debt', async () => { + // const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); + // const withdrawAmount = supplyAmount; + // const deployerJettonBalanceBefore = (await deployerJettonDefaultWallet.getGetWalletData()).balance; + // const result = await pool.send( + // deployer.getSender(), + // { + // value: toNano('0.5'), + // }, + // { + // $$type: 'WithdrawToken', + // tokenAddress: sampleJetton.address, + // amount: withdrawAmount, + // }, + // ); + + // // WithdrawToken + // expect(result.transactions).toHaveTransaction({ + // from: deployer.address, + // to: pool.address, + // success: true, + // }); + + // // GetUserAccountData + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserAccountDataResponse + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: true, + // }); + + // // sendTokenTransferByPool TokenTransfer + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: poolWallet.address, + // success: true, + // }); + + // // UpdatePosition + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserPositionUpdated + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: true, + // }); + + // // Burn aToken + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: deployerATokenDefaultWallet.address, + // success: true, + // }); + + // // aToken-wallet to aToken-master TokenBurnNotification + // expect(result.transactions).toHaveTransaction({ + // from: deployerATokenDefaultWallet.address, + // to: aToken.address, + // success: true, + // }); + + // const userAccountContract = blockchain.openContract(userAccountAddress); + // const accountData = await userAccountContract.getAccount(); + // expect(accountData.positionsLength).toEqual(1n); + // expect(accountData.positions?.get(0n)!!.equals(sampleJetton.address)).toBeTruthy(); + // expect(accountData.positionsDetail?.get(sampleJetton.address)!!.supply).toEqual(supplyAmount - withdrawAmount); + // expect(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow).toEqual(toNano(0n)); + + // const walletData = await deployerATokenDefaultWallet.getGetWalletData(); + // expect(walletData.balance).toEqual(supplyAmount - withdrawAmount); + // expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( + // deployerJettonBalanceBefore + withdrawAmount, + // ); + // }); + + // it('withdraw max amount when user have the debt and check HF successfully', async () => { + // const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); + // const userAccountContract = blockchain.openContract(userAccountAddress); + + // const borrowAmount = toNano(60n); + // await borrowFromDeployer(borrowAmount / 2n); + // await sleep(5 * 1000); + // await borrowFromDeployer(borrowAmount / 2n); + + // const maxWithdrawAmount = + // supplyAmount - (borrowAmount * PERCENTAGE_FACTOR) / reserveConfiguration.liquidationThreshold; + // // withdraw + // const withdrawAmount = maxWithdrawAmount - toNano('0.01'); + // const deployerJettonBalanceBefore = (await deployerJettonDefaultWallet.getGetWalletData()).balance; + // let result = await pool.send( + // deployer.getSender(), + // { + // value: toNano('1.5'), + // }, + // { + // $$type: 'WithdrawToken', + // tokenAddress: sampleJetton.address, + // amount: withdrawAmount, + // }, + // ); + + // // WithdrawToken + // expect(result.transactions).toHaveTransaction({ + // from: deployer.address, + // to: pool.address, + // success: true, + // }); + + // // GetUserAccountData + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserAccountDataResponse + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: true, + // }); + + // // sendTokenTransferByPool TokenTransfer + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: poolWallet.address, + // success: true, + // }); + + // // UpdatePosition + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserPositionUpdated + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: true, + // }); + + // // Burn aToken + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: deployerATokenDefaultWallet.address, + // success: true, + // }); + + // // aToken-wallet to aToken-master TokenBurnNotification + // expect(result.transactions).toHaveTransaction({ + // from: deployerATokenDefaultWallet.address, + // to: aToken.address, + // success: true, + // }); + + // let accountData = await userAccountContract.getAccount(); + + // expect(Number(fromNano(accountData.positionsDetail?.get(sampleJetton.address)!!.supply))).toBeCloseTo( + // Number(fromNano(supplyAmount - withdrawAmount)), + // 5, + // ); + // expect(Number(fromNano(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow))).toBeCloseTo( + // Number(fromNano(borrowAmount)), + // 5, + // ); + + // const walletData = await deployerATokenDefaultWallet.getGetWalletData(); + // expect(Number(fromNano(walletData.balance))).toBeCloseTo(Number(fromNano(supplyAmount - withdrawAmount)), 5); + // expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( + // deployerJettonBalanceBefore + withdrawAmount, + // ); + // }); + + // it('should bounce if the left supply position cant cover the debt', async () => { + // const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); + + // const borrowAmount = toNano(60n); + // await borrowFromDeployer(borrowAmount); + + // const maxWithdrawAmount = + // supplyAmount - (borrowAmount * PERCENTAGE_FACTOR) / reserveConfiguration.liquidationThreshold; + // // withdraw + // let result = await pool.send( + // deployer.getSender(), + // { + // value: toNano('1.5'), + // }, + // { + // $$type: 'WithdrawToken', + // tokenAddress: sampleJetton.address, + // amount: maxWithdrawAmount + 2n, + // }, + // ); + + // // WithdrawToken + // expect(result.transactions).toHaveTransaction({ + // from: deployer.address, + // to: pool.address, + // success: true, + // }); + + // // GetUserAccountData + // expect(result.transactions).toHaveTransaction({ + // from: pool.address, + // to: userAccountAddress.address, + // success: true, + // }); + + // // UserAccountDataResponse + // expect(result.transactions).toHaveTransaction({ + // from: userAccountAddress.address, + // to: pool.address, + // success: false, + // }); + // }); + + it('withdraw Bounce and rerun', async () => { + const userAccount = await UserAccount.fromInit(pool.address, deployer.address); const withdrawAmount = toNano(50n); const deployerJettonBalanceBefore = (await deployerJettonDefaultWallet.getGetWalletData()).balance; - const result = await pool.send( + let result = await pool.send( deployer.getSender(), { - value: toNano('1.5'), + value: toNano('0.05'), }, { $$type: 'WithdrawToken', @@ -332,13 +653,13 @@ describe('Pool Withdraw', () => { // GetUserAccountData expect(result.transactions).toHaveTransaction({ from: pool.address, - to: userAccountAddress.address, + to: userAccount.address, success: true, }); // UserAccountDataResponse expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, + from: userAccount.address, to: pool.address, success: true, }); @@ -353,193 +674,94 @@ describe('Pool Withdraw', () => { // UpdatePosition expect(result.transactions).toHaveTransaction({ from: pool.address, - to: userAccountAddress.address, - success: true, - }); - - // UserPositionUpdated - expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, - to: pool.address, - success: true, - }); - - // Burn aToken - expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: deployerATokenDefaultWallet.address, - success: true, - }); - - // aToken-wallet to aToken-master TokenBurnNotification - expect(result.transactions).toHaveTransaction({ - from: deployerATokenDefaultWallet.address, - to: aToken.address, - success: true, + to: userAccount.address, + success: false, }); - const userAccountContract = blockchain.openContract(userAccountAddress); - const accountData = await userAccountContract.getAccount(); - expect(accountData.positionsDetail?.get(sampleJetton.address)!!.supply).toEqual(supplyAmount - withdrawAmount); - expect(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow).toEqual(toNano(0n)); + let msgId = (await pool.getQueryId()) - 1n; + const updatePositionBounce = parsePoolBounceMessage(await pool.getBounceMsg(msgId)) as UpdatePositionBounce; + expect(updatePositionBounce.$$type).toEqual('UpdatePositionBounce'); + expect(updatePositionBounce.to.toString()).toEqual(userAccount.address.toString()); + expect(updatePositionBounce.user.toString()).toEqual(deployer.getSender().address.toString()); + expect(updatePositionBounce.msg.$$type).toEqual('UpdatePosition'); + expect(updatePositionBounce.msg.queryId).toEqual(msgId); + expect(updatePositionBounce.msg.address.toString()).toEqual(sampleJetton.address.toString()); + expect(updatePositionBounce.msg.supply).toEqual(-withdrawAmount); + expect(updatePositionBounce.msg.borrow).toEqual(0n); - const walletData = await deployerATokenDefaultWallet.getGetWalletData(); - expect(walletData.balance).toEqual(supplyAmount - withdrawAmount); - expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( - deployerJettonBalanceBefore + withdrawAmount, - ); - }); - - it('withdraw max amount successfully with no debt', async () => { - const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); - const withdrawAmount = supplyAmount; - const deployerJettonBalanceBefore = (await deployerJettonDefaultWallet.getGetWalletData()).balance; - const result = await pool.send( + result = await pool.send( deployer.getSender(), { - value: toNano('0.5'), + value: toNano('0.06'), }, { - $$type: 'WithdrawToken', - tokenAddress: sampleJetton.address, - amount: withdrawAmount, + $$type: 'RerunBounceMsg', + queryId: msgId, + action: RERUN_ACTION_UPDATE_POSITION, }, ); - // WithdrawToken + // RerunBounceMsg expect(result.transactions).toHaveTransaction({ - from: deployer.address, + from: deployer.getSender().address, to: pool.address, success: true, }); - - // GetUserAccountData + // UpdatePosition expect(result.transactions).toHaveTransaction({ from: pool.address, - to: userAccountAddress.address, + to: userAccount.address, success: true, }); - - // UserAccountDataResponse + // UserPositionUpdated expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, + from: userAccount.address, to: pool.address, success: true, }); - // sendTokenTransferByPool TokenTransfer - expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: poolWallet.address, - success: true, - }); - - // UpdatePosition - expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: userAccountAddress.address, - success: true, - }); - // UserPositionUpdated expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, + from: userAccount.address, to: pool.address, success: true, }); + expect(await pool.getBounceMsg(msgId)).toEqual(null); + // Burn aToken expect(result.transactions).toHaveTransaction({ from: pool.address, to: deployerATokenDefaultWallet.address, - success: true, - }); - - // aToken-wallet to aToken-master TokenBurnNotification - expect(result.transactions).toHaveTransaction({ - from: deployerATokenDefaultWallet.address, - to: aToken.address, - success: true, + success: false, }); - const userAccountContract = blockchain.openContract(userAccountAddress); - const accountData = await userAccountContract.getAccount(); - expect(accountData.positionsLength).toEqual(1n); - expect(accountData.positions?.get(0n)!!.equals(sampleJetton.address)).toBeTruthy(); - expect(accountData.positionsDetail?.get(sampleJetton.address)!!.supply).toEqual(supplyAmount - withdrawAmount); - expect(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow).toEqual(toNano(0n)); - - const walletData = await deployerATokenDefaultWallet.getGetWalletData(); - expect(walletData.balance).toEqual(supplyAmount - withdrawAmount); - expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( - deployerJettonBalanceBefore + withdrawAmount, - ); - }); - - it('withdraw max amount when user have the debt and check HF successfully', async () => { - const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); - const userAccountContract = blockchain.openContract(userAccountAddress); - - const borrowAmount = toNano(60n); - await borrowFromDeployer(borrowAmount / 2n); - await sleep(5 * 1000); - await borrowFromDeployer(borrowAmount / 2n); + msgId = (await pool.getQueryId()) - 1n; + const tokenBurnBounce = parsePoolBounceMessage(await pool.getBounceMsg(msgId)) as TokenBurnBounce; + expect(tokenBurnBounce.$$type).toEqual('TokenBurnBounce'); + expect(tokenBurnBounce.to.toString()).toEqual(deployerATokenDefaultWallet.address.toString()); + expect(tokenBurnBounce.user.toString()).toEqual(deployer.getSender().address.toString()); + expect(tokenBurnBounce.msg.$$type).toEqual('TokenBurn'); + expect(tokenBurnBounce.msg.queryId).toEqual(msgId); + expect(tokenBurnBounce.msg.amount).toEqual(withdrawAmount); + expect(tokenBurnBounce.msg.owner.toString()).toEqual(deployer.getSender().address.toString()); + expect(tokenBurnBounce.msg.response_destination.toString()).toEqual(pool.address.toString()); - const maxWithdrawAmount = - supplyAmount - (borrowAmount * PERCENTAGE_FACTOR) / reserveConfiguration.liquidationThreshold; - // withdraw - const withdrawAmount = maxWithdrawAmount - toNano('0.01'); - const deployerJettonBalanceBefore = (await deployerJettonDefaultWallet.getGetWalletData()).balance; - let result = await pool.send( + result = await pool.send( deployer.getSender(), { - value: toNano('1.5'), + value: toNano('0.05'), }, { - $$type: 'WithdrawToken', - tokenAddress: sampleJetton.address, - amount: withdrawAmount, + $$type: 'RerunBounceMsg', + queryId: msgId, + action: RERUN_ACTION_TOKEN_BURN, }, ); - // WithdrawToken - expect(result.transactions).toHaveTransaction({ - from: deployer.address, - to: pool.address, - success: true, - }); - - // GetUserAccountData - expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: userAccountAddress.address, - success: true, - }); - - // UserAccountDataResponse - expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, - to: pool.address, - success: true, - }); - - // sendTokenTransferByPool TokenTransfer + // RerunBounceMsg expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: poolWallet.address, - success: true, - }); - - // UpdatePosition - expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: userAccountAddress.address, - success: true, - }); - - // UserPositionUpdated - expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, + from: deployer.getSender().address, to: pool.address, success: true, }); @@ -558,64 +780,23 @@ describe('Pool Withdraw', () => { success: true, }); - let accountData = await userAccountContract.getAccount(); - - expect(Number(fromNano(accountData.positionsDetail?.get(sampleJetton.address)!!.supply))).toBeCloseTo( - Number(fromNano(supplyAmount - withdrawAmount)), - 5, - ); - expect(Number(fromNano(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow))).toBeCloseTo( - Number(fromNano(borrowAmount)), - 5, - ); - - const walletData = await deployerATokenDefaultWallet.getGetWalletData(); - expect(Number(fromNano(walletData.balance))).toBeCloseTo(Number(fromNano(supplyAmount - withdrawAmount)), 5); - expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( - deployerJettonBalanceBefore + withdrawAmount, - ); - }); - - it('should bounce if the left supply position cant cover the debt', async () => { - const userAccountAddress = await UserAccount.fromInit(pool.address, deployer.address); - - const borrowAmount = toNano(60n); - await borrowFromDeployer(borrowAmount); - - const maxWithdrawAmount = - supplyAmount - (borrowAmount * PERCENTAGE_FACTOR) / reserveConfiguration.liquidationThreshold; - // withdraw - let result = await pool.send( - deployer.getSender(), - { - value: toNano('1.5'), - }, - { - $$type: 'WithdrawToken', - tokenAddress: sampleJetton.address, - amount: maxWithdrawAmount + 2n, - }, - ); - - // WithdrawToken + // TokenExcesses expect(result.transactions).toHaveTransaction({ - from: deployer.address, + from: aToken.address, to: pool.address, success: true, }); + expect(await pool.getBounceMsg(msgId)).toEqual(null); - // GetUserAccountData - expect(result.transactions).toHaveTransaction({ - from: pool.address, - to: userAccountAddress.address, - success: true, - }); + const userAccountContract = blockchain.openContract(userAccount); + const accountData = await userAccountContract.getAccount(); + expect(accountData.positionsDetail?.get(sampleJetton.address)!!.supply).toEqual(supplyAmount - withdrawAmount); + expect(accountData.positionsDetail?.get(sampleJetton.address)!!.borrow).toEqual(toNano(0n)); - // UserAccountDataResponse - expect(result.transactions).toHaveTransaction({ - from: userAccountAddress.address, - to: pool.address, - success: false, - }); + const walletData = await deployerATokenDefaultWallet.getGetWalletData(); + expect(walletData.balance).toEqual(supplyAmount - withdrawAmount); + expect((await deployerJettonDefaultWallet.getGetWalletData()).balance).toEqual( + deployerJettonBalanceBefore + withdrawAmount, + ); }); }); diff --git a/tests/SampleJetton.spec.ts b/tests/SampleJetton.spec.ts index 5d097e0..95a5b72 100644 --- a/tests/SampleJetton.spec.ts +++ b/tests/SampleJetton.spec.ts @@ -58,7 +58,6 @@ describe('SampleJetton', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, amount: 1000000000n, receiver: receiverAddress, }, diff --git a/tests/TestJettonReceive.spec.ts b/tests/TestJettonReceive.spec.ts index 58a8d8e..34d2800 100644 --- a/tests/TestJettonReceive.spec.ts +++ b/tests/TestJettonReceive.spec.ts @@ -54,7 +54,6 @@ describe('TestJettonReceive', () => { { $$type: 'Mint', queryId: 0n, - token: sampleJetton.address, receiver: deployer.getSender().address, amount: toNano(100000), }, diff --git a/tests/UserAccount.spec.ts b/tests/UserAccount.spec.ts index 75732ef..f583523 100644 --- a/tests/UserAccount.spec.ts +++ b/tests/UserAccount.spec.ts @@ -43,7 +43,6 @@ describe('UserAccoount', () => { { $$type: 'UpdatePosition', queryId: 1n, - user: deployer.getSender().address, address: reserveAddress, supply: toNano('100'), borrow: 0n, @@ -72,7 +71,6 @@ describe('UserAccoount', () => { { $$type: 'UpdatePosition', queryId: 1n, - user: deployer.getSender().address, address: reserveAddress, supply: toNano('100'), borrow: 0n, @@ -87,7 +85,6 @@ describe('UserAccoount', () => { { $$type: 'UpdatePosition', queryId: 1n, - user: deployer.getSender().address, address: reserveAddress, supply: -toNano('50'), borrow: toNano(20n),