From e2da312cfce035e6d5a33f524dd75468a441d66e Mon Sep 17 00:00:00 2001 From: Victoria Erokhina Date: Wed, 9 Oct 2024 11:22:21 +0000 Subject: [PATCH] Add simple v2 straw --- pkg/bath/stonfi.go | 115 ++++++++++++++++++++++++++++++++++++++ pkg/core/trace.go | 19 ++++++- pkg/litestorage/stonfi.go | 64 +++++++++++++-------- 3 files changed, 173 insertions(+), 25 deletions(-) diff --git a/pkg/bath/stonfi.go b/pkg/bath/stonfi.go index 46dcd873..2a6ff38c 100644 --- a/pkg/bath/stonfi.go +++ b/pkg/bath/stonfi.go @@ -122,6 +122,121 @@ var StonfiSwapStraw = Straw[BubbleJettonSwap]{ }, } +var StonfiV2PTONStraw = Straw[BubbleJettonTransfer]{ + CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.JettonWallet), HasOperation(abi.JettonTransferMsgOp)}, + Builder: func(newAction *BubbleJettonTransfer, bubble *Bubble) error { + tx := bubble.Info.(BubbleTx) + newAction.master, _ = tx.additionalInfo.JettonMaster(tx.account.Address) + newAction.senderWallet = tx.account.Address + newAction.sender = tx.inputFrom + body := tx.decodedBody.Value.(abi.JettonTransferMsgBody) + newAction.amount = body.Amount + newAction.isWrappedTon = true + recipient, err := ton.AccountIDFromTlb(body.Destination) + if err == nil { + newAction.recipient = &Account{Address: *recipient} + } + return nil + }, + SingleChild: &Straw[BubbleJettonTransfer]{ + CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonNotifyMsgOp)}, + Builder: func(newAction *BubbleJettonTransfer, bubble *Bubble) error { + tx := bubble.Info.(BubbleTx) + newAction.success = true + body := tx.decodedBody.Value.(abi.JettonNotifyMsgBody) + newAction.amount = body.Amount + newAction.payload = body.ForwardPayload.Value + newAction.recipient = &tx.account + return nil + }, + }, +} + +var StonfiSwapV2Straw = Straw[BubbleJettonSwap]{ + CheckFuncs: []bubbleCheck{func(bubble *Bubble) bool { + jettonTx, ok := bubble.Info.(BubbleJettonTransfer) + if !ok { + return false + } + if jettonTx.sender == nil { + return false + } + if jettonTx.payload.SumType != abi.StonfiSwapV2JettonOp { + return false + } + swap, ok := jettonTx.payload.Value.(abi.StonfiSwapV2JettonPayload) + if !ok { + return false + } + to, err := ton.AccountIDFromTlb(swap.CrossSwapBody.Receiver) + if err != nil || to == nil { + return false + } + if jettonTx.sender.Address != *to { //protection against invalid swaps + return false + } + return true + }}, + Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error { + newAction.Dex = Stonfi + jettonTx := bubble.Info.(BubbleJettonTransfer) + newAction.UserWallet = jettonTx.sender.Address + newAction.In.Amount = big.Int(jettonTx.amount) + newAction.In.IsTon = jettonTx.isWrappedTon + newAction.In.JettonMaster = jettonTx.master + return nil + }, + SingleChild: &Straw[BubbleJettonSwap]{ + CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.StonfiSwapV2MsgOp), HasInterface(abi.StonfiPoolV2)}, + Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error { + tx := bubble.Info.(BubbleTx) + a, b := tx.additionalInfo.STONfiPool.Token0, tx.additionalInfo.STONfiPool.Token1 + body := tx.decodedBody.Value.(abi.StonfiSwapV2MsgBody) + if body.QueryId > 0 && a.IsZero() && b.IsZero() { + return nil + } + //newAction.Out.Amount = big.Int(body.MinOut) + //s, err := tongo.AccountIDFromTlb(body.SenderAddress) + //if err != nil { + // return err + //} + //if s != nil && *s == b { + // a, b = b, a + //} + //newAction.In.JettonWallet = a + //newAction.Out.JettonWallet = b + //if tx.additionalInfo != nil { + // newAction.In.JettonMaster, _ = tx.additionalInfo.JettonMaster(a) + // newAction.Out.JettonMaster, _ = tx.additionalInfo.JettonMaster(b) + //} + return nil + }, + SingleChild: &Straw[BubbleJettonSwap]{ + CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.StonfiPayToV2MsgOp)}, + Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error { + tx := bubble.Info.(BubbleTx) + newAction.Router = tx.account.Address + return nil + }, + SingleChild: &Straw[BubbleJettonSwap]{ + CheckFuncs: []bubbleCheck{Is(BubbleJettonTransfer{})}, + Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error { + jettonTx := bubble.Info.(BubbleJettonTransfer) + if jettonTx.senderWallet != newAction.Out.JettonWallet { + // operation has failed, + // stonfi's sent jettons back to the user + return nil + } + newAction.Out.Amount = big.Int(jettonTx.amount) + newAction.Out.IsTon = jettonTx.isWrappedTon + newAction.Success = true + return nil + }, + }, + }, + }, +} + // https://dev.tonviewer.com/transaction/e19381edd8f05922eeba3c31f4b8b4b737478b4ca7b37130bdbbfd7bfa773227 // todo: add liquidity (mint lp tokens) var StonfiMintStraw = Straw[BubbleJettonMint]{} diff --git a/pkg/core/trace.go b/pkg/core/trace.go index bb86fb4b..3b499100 100644 --- a/pkg/core/trace.go +++ b/pkg/core/trace.go @@ -101,6 +101,18 @@ type STONfiPool struct { Token1 tongo.AccountID } +type STONfiVersion string + +const ( + STONfiPoolV1 STONfiVersion = "v1" + STONfiPoolV2 STONfiVersion = "v2" +) + +type STONfiPoolID struct { + ID tongo.AccountID + Version STONfiVersion +} + // InformationSource provides methods to construct TraceAdditionalInfo. type InformationSource interface { JettonMastersForWallets(ctx context.Context, wallets []tongo.AccountID) (map[tongo.AccountID]tongo.AccountID, error) @@ -151,7 +163,7 @@ func CollectAdditionalInfo(ctx context.Context, infoSource InformationSource, tr } var jettonWallets []tongo.AccountID var saleContracts []tongo.AccountID - var stonfiPoolIDs []tongo.AccountID + var stonfiPoolIDs []STONfiPoolID Visit(trace, func(trace *Trace) { // when we emulate a trace, // we construct "trace.AdditionalInfo" in emulatedTreeToTrace for all accounts the trace touches. @@ -169,7 +181,10 @@ func CollectAdditionalInfo(ctx context.Context, infoSource InformationSource, tr saleContracts = append(saleContracts, trace.Account) } if hasInterface(trace.AccountInterfaces, abi.StonfiPool) { - stonfiPoolIDs = append(stonfiPoolIDs, trace.Account) + stonfiPoolIDs = append(stonfiPoolIDs, STONfiPoolID{ID: trace.Account, Version: STONfiPoolV1}) + } + if hasInterface(trace.AccountInterfaces, abi.StonfiPoolV2) { + stonfiPoolIDs = append(stonfiPoolIDs, STONfiPoolID{ID: trace.Account, Version: STONfiPoolV2}) } }) stonfiPools, err := infoSource.STONfiPools(ctx, stonfiPoolIDs) diff --git a/pkg/litestorage/stonfi.go b/pkg/litestorage/stonfi.go index edc1ee02..e6f1c426 100644 --- a/pkg/litestorage/stonfi.go +++ b/pkg/litestorage/stonfi.go @@ -8,34 +8,52 @@ import ( "github.com/tonkeeper/tongo/abi" ) -func (s *LiteStorage) STONfiPools(ctx context.Context, poolIDs []tongo.AccountID) (map[tongo.AccountID]core.STONfiPool, error) { +func (s *LiteStorage) STONfiPools(ctx context.Context, poolIDs []core.STONfiPoolID) (map[tongo.AccountID]core.STONfiPool, error) { pools := make(map[tongo.AccountID]core.STONfiPool) for _, poolID := range poolIDs { - _, value, err := abi.GetPoolData(ctx, s.executor, poolID) + _, value, err := abi.GetPoolData(ctx, s.executor, poolID.ID) if err != nil { return nil, err } - result, ok := value.(abi.GetPoolData_StonfiResult) - if !ok { - continue - } - token0, err := tongo.AccountIDFromTlb(result.Token0Address) - if err != nil { - return nil, err - } - if token0 == nil { - continue - } - token1, err := tongo.AccountIDFromTlb(result.Token1Address) - if err != nil { - return nil, err - } - if token1 == nil { - continue - } - pools[poolID] = core.STONfiPool{ - Token0: *token0, - Token1: *token1, + switch result := value.(type) { + case abi.GetPoolData_StonfiResult: + token0, err := tongo.AccountIDFromTlb(result.Token0Address) + if err != nil { + return nil, err + } + if token0 == nil { + continue + } + token1, err := tongo.AccountIDFromTlb(result.Token1Address) + if err != nil { + return nil, err + } + if token1 == nil { + continue + } + pools[poolID.ID] = core.STONfiPool{ + Token0: *token0, + Token1: *token1, + } + case abi.GetPoolData_StonfiV2Result: + token0, err := tongo.AccountIDFromTlb(result.Token0WalletAddress) + if err != nil { + return nil, err + } + if token0 == nil { + continue + } + token1, err := tongo.AccountIDFromTlb(result.Token1WalletAddress) + if err != nil { + return nil, err + } + if token1 == nil { + continue + } + pools[poolID.ID] = core.STONfiPool{ + Token0: *token0, + Token1: *token1, + } } } return pools, nil