bath

package
v0.0.0-...-4fc17d7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 14, 2024 License: MIT Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	TonTransfer           ActionType = "TonTransfer"
	SmartContractExec     ActionType = "SmartContractExec"
	NftItemTransfer       ActionType = "NftItemTransfer"
	NftPurchase           ActionType = "NftPurchase"
	JettonTransfer        ActionType = "JettonTransfer"
	JettonMint            ActionType = "JettonMint"
	JettonBurn            ActionType = "JettonBurn"
	ContractDeploy        ActionType = "ContractDeploy"
	Subscription          ActionType = "Subscribe"
	UnSubscription        ActionType = "UnSubscribe"
	ElectionsDepositStake ActionType = "ElectionsDepositStake"
	ElectionsRecoverStake ActionType = "ElectionsRecoverStake"
	DepositStake          ActionType = "DepositStake"
	WithdrawStake         ActionType = "WithdrawStake"
	WithdrawStakeRequest  ActionType = "WithdrawStakeRequest"
	JettonSwap            ActionType = "JettonSwap"
	AuctionBid            ActionType = "AuctionBid"
	DomainRenew           ActionType = "DomainRenew"
	InscriptionMint       ActionType = "InscriptionMint"
	InscriptionTransfer   ActionType = "InscriptionTransfer"

	RefundDnsTg   RefundType = "DNS.tg"
	RefundDnsTon  RefundType = "DNS.ton"
	RefundGetGems RefundType = "GetGems"
	RefundUnknown RefundType = "unknown"
)
View Source
const (
	GetGemsAuction  NftAuctionType = "getgems"
	DnsTonAuction                  = "DNS.ton"
	DnsTgAuction                   = "DNS.tg"
	NumberTgAuction                = "NUMBER.tg"
)

Variables

View Source
var DNSRenewStraw = Straw[BubbleDnsItemRenew]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DeleteDnsRecordMsgOp), HasInterface(abi.NftItem), func(bubble *Bubble) bool {
		return bubble.Info.(BubbleTx).decodedBody.Value.(abi.DeleteDnsRecordMsgBody).Key.Equal(tlb.Bits256{})
	}},
	Builder: func(newAction *BubbleDnsItemRenew, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Renewer = tx.inputFrom.Address
		newAction.Item = tx.account.Address
		newAction.Success = tx.success
		return nil
	},
	SingleChild: &Straw[BubbleDnsItemRenew]{
		Optional:   true,
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.BounceMsgOp)},
	},
}
View Source
var DedustLPJettonMintStraw = Straw[BubbleJettonMint]{
	CheckFuncs: []bubbleCheck{IsTx, Or(HasOpcode(0xb56b9598), HasOpcode(0x1674b0a0))},
	Builder: func(newAction *BubbleJettonMint, bubble *Bubble) (err error) {
		tx := bubble.Info.(BubbleTx)
		newAction.master = tx.account.Address
		return nil
	},
	Children: []Straw[BubbleJettonMint]{
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonInternalTransferMsgOp)},
			Builder: func(newAction *BubbleJettonMint, bubble *Bubble) error {
				tx := bubble.Info.(BubbleTx)
				msg := tx.decodedBody.Value.(abi.JettonInternalTransferMsgBody)
				newAction.amount = msg.Amount
				newAction.recipientWallet = tx.account.Address
				newAction.success = tx.success
				return nil
			},
			Children: []Straw[BubbleJettonMint]{
				{
					CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonNotifyMsgOp)},
					Builder: func(newAction *BubbleJettonMint, bubble *Bubble) error {
						tx := bubble.Info.(BubbleTx)
						newAction.recipient = tx.account
						return nil
					},
				},
				{CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)}, Optional: true},
			},
		},
	},
}

DedustLPJettonMintStraw example: https://tonviewer.com/transaction/6d33487c44249d7844db8fac38a5cecf1502ec7e0c09d266e98e95a2b1be17b5

View Source
var DedustSwapFromTONStraw = Straw[BubbleJettonSwap]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustSwapJettonOp), func(bubble *Bubble) bool {
		tx := bubble.Info.(BubbleTx)
		swap, ok := tx.decodedBody.Value.(abi.DedustSwapMsgBody)
		if !ok {
			return false
		}
		to, err := ton.AccountIDFromTlb(swap.SwapParams.RecipientAddr)
		if err != nil {
			return false
		}
		if to == nil {
			return true
		}

		if tx.inputFrom == nil || tx.inputFrom.Address != *to {
			return false
		}
		return true
	}},
	Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
		transfer := bubble.Info.(BubbleTx)
		newAction.Success = true
		newAction.Dex = Dedust
		if transfer.inputFrom != nil {
			newAction.UserWallet = transfer.inputFrom.Address
		}
		newAction.In.IsTon = true
		newAction.In.Amount.SetInt64(transfer.inputAmount)
		return nil
	},
	SingleChild: &Straw[BubbleJettonSwap]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustSwapExternalMsgOp), HasInterface(abi.DedustPool)},
		Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
			newAction.Router = bubble.Info.(BubbleTx).account.Address
			return nil
		},
		SingleChild: &Straw[BubbleJettonSwap]{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustPayoutFromPoolMsgOp), HasInterface(abi.DedustVault)},
			SingleChild: &Straw[BubbleJettonSwap]{
				CheckFuncs: []bubbleCheck{Or(IsJettonTransfer, IsTx)},
				Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
					if IsJettonTransfer(bubble) {
						transfer := bubble.Info.(BubbleJettonTransfer)
						newAction.Out.JettonMaster = transfer.master
						newAction.Out.Amount = big.Int(transfer.amount)
						newAction.Out.JettonWallet = transfer.recipientWallet
						newAction.UserWallet = transfer.recipient.Address
					} else {
						transfer := bubble.Info.(BubbleTx)
						newAction.Success = false
						newAction.Out.IsTon = true
						newAction.Out.Amount.SetInt64(transfer.inputAmount)
						newAction.Out.JettonWallet = transfer.inputFrom.Address
						newAction.UserWallet = transfer.account.Address
					}
					return nil
				},
			},
		},
	},
}
View Source
var DedustSwapJettonsStraw = Straw[BubbleJettonSwap]{
	CheckFuncs: []bubbleCheck{IsJettonTransfer, JettonTransferOperation(abi.DedustSwapJettonOp), func(bubble *Bubble) bool {
		transfer := bubble.Info.(BubbleJettonTransfer)
		swap, ok := transfer.payload.Value.(abi.DedustSwapJettonPayload)
		if !ok {
			return false
		}
		to, err := ton.AccountIDFromTlb(swap.SwapParams.RecipientAddr)
		if err != nil {
			return false
		}
		if to == nil {
			return true
		}

		if transfer.sender == nil || transfer.sender.Address != *to {
			return false
		}
		return true
	}},
	Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
		transfer := bubble.Info.(BubbleJettonTransfer)
		newAction.Success = true
		newAction.Dex = Dedust
		if transfer.sender != nil {
			newAction.UserWallet = transfer.sender.Address
		}
		newAction.In.JettonMaster = transfer.master
		newAction.In.JettonWallet = transfer.senderWallet
		newAction.In.Amount = big.Int(transfer.amount)
		newAction.In.IsTon = transfer.isWrappedTon
		if transfer.payload.Value.(abi.DedustSwapJettonPayload).Step.Params.KindOut {
			return errors.New("dedust swap: wrong kind of limits")
		}
		newAction.Out.Amount = big.Int(transfer.payload.Value.(abi.DedustSwapJettonPayload).Step.Params.Limit)
		return nil
	},
	SingleChild: &Straw[BubbleJettonSwap]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustSwapExternalMsgOp)},
		Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
			newAction.Router = bubble.Info.(BubbleTx).account.Address
			return nil
		},
		SingleChild: &Straw[BubbleJettonSwap]{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustPayoutFromPoolMsgOp), HasInterface(abi.DedustVault)},
			SingleChild: &Straw[BubbleJettonSwap]{
				CheckFuncs: []bubbleCheck{IsJettonTransfer},
				Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
					newAction.Success = true
					transfer := bubble.Info.(BubbleJettonTransfer)
					newAction.Out.JettonMaster = transfer.master
					newAction.Out.IsTon = transfer.isWrappedTon
					newAction.Out.Amount = big.Int(transfer.amount)
					newAction.Out.JettonWallet = transfer.recipientWallet
					return nil
				},
			},
		},
	},
}
View Source
var DedustSwapToTONStraw = Straw[BubbleJettonSwap]{
	CheckFuncs: []bubbleCheck{IsJettonTransfer, JettonTransferOperation(abi.DedustSwapJettonOp), func(bubble *Bubble) bool {
		transfer := bubble.Info.(BubbleJettonTransfer)
		swap, ok := transfer.payload.Value.(abi.DedustSwapJettonPayload)
		if !ok {
			return false
		}
		to, err := ton.AccountIDFromTlb(swap.SwapParams.RecipientAddr)
		if err != nil {
			return false
		}
		if to == nil {
			return true
		}

		if transfer.sender == nil || transfer.sender.Address != *to {
			return false
		}
		return true
	}},
	Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
		transfer := bubble.Info.(BubbleJettonTransfer)
		newAction.Success = true
		newAction.Dex = Dedust
		if transfer.sender != nil {
			newAction.UserWallet = transfer.sender.Address
		}
		newAction.In.JettonMaster = transfer.master
		newAction.In.JettonWallet = transfer.senderWallet
		newAction.In.Amount = big.Int(transfer.amount)
		newAction.In.IsTon = transfer.isWrappedTon
		if transfer.payload.Value.(abi.DedustSwapJettonPayload).Step.Params.KindOut {
			return errors.New("dedust swap: wrong kind of limits")
		}
		return nil
	},
	SingleChild: &Straw[BubbleJettonSwap]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustSwapExternalMsgOp)},
		Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
			newAction.Router = bubble.Info.(BubbleTx).account.Address
			return nil
		},
		SingleChild: &Straw[BubbleJettonSwap]{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.DedustPayoutFromPoolMsgOp), HasInterface(abi.DedustVault)},
			SingleChild: &Straw[BubbleJettonSwap]{
				CheckFuncs: []bubbleCheck{IsTx, HasOperation("DedustPayout")},
				Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
					transfer := bubble.Info.(BubbleTx)
					newAction.Out.IsTon = true
					newAction.Out.Amount.SetInt64(transfer.inputAmount)
					return nil
				},
			},
		},
	},
}
View Source
var DepositLiquidStakeStraw = Straw[BubbleDepositStake]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.TonstakePoolDepositMsgOp)},
	Builder: func(newAction *BubbleDepositStake, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Pool = tx.account.Address
		newAction.Staker = tx.inputFrom.Address
		newAction.Amount = tx.inputAmount - int64(ton.OneTON)
		if newAction.Amount < 0 {
			newAction.Amount = 0
		}
		newAction.Success = tx.success
		newAction.Implementation = core.StakingImplementationLiquidTF
		return nil
	},
	SingleChild: &Straw[BubbleDepositStake]{
		CheckFuncs: []bubbleCheck{IsBounced},
		Optional:   true,
	},
}
View Source
var DepositTFStakeStraw = Straw[BubbleDepositStake]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.TvPool), HasTextComment("d")},
	Builder: func(newAction *BubbleDepositStake, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Pool = tx.account.Address
		newAction.Staker = tx.inputFrom.Address
		newAction.Amount = tx.inputAmount
		newAction.Success = tx.success
		newAction.Implementation = core.StakingImplementationTF
		return nil
	},
	SingleChild: &Straw[BubbleDepositStake]{
		CheckFuncs: []bubbleCheck{IsBounced},
		Optional:   true,
	},
}
View Source
var ElectionsDepositStakeStraw = Straw[BubbleElectionsDepositStake]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ElectorNewStakeMsgOp), IsAccount(config.ElectorAddress())},
	Builder: func(newAction *BubbleElectionsDepositStake, bubble *Bubble) error {
		bubbleTx := bubble.Info.(BubbleTx)
		newAction.Amount = bubbleTx.inputAmount
		newAction.Staker = bubbleTx.inputFrom.Address
		return nil
	},
	Children: []Straw[BubbleElectionsDepositStake]{
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ElectorNewStakeConfirmationMsgOp)},
			Builder: func(newAction *BubbleElectionsDepositStake, bubble *Bubble) error {
				newAction.Success = true
				return nil
			},
		},
	},
}
View Source
var ElectionsRecoverStakeStraw = Straw[BubbleElectionsRecoverStake]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ElectorRecoverStakeRequestMsgOp), IsAccount(config.ElectorAddress())},
	Builder: func(newAction *BubbleElectionsRecoverStake, bubble *Bubble) error {
		bubbleTx := bubble.Info.(BubbleTx)
		newAction.Staker = bubbleTx.inputFrom.Address
		return nil
	},
	Children: []Straw[BubbleElectionsRecoverStake]{
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ElectorRecoverStakeResponseMsgOp)},
			Builder: func(newAction *BubbleElectionsRecoverStake, bubble *Bubble) error {
				newAction.Amount = bubble.Info.(BubbleTx).inputAmount
				newAction.Success = true
				return nil
			},
		},
	},
}
View Source
var ExtendedSubscriptionStraw = Straw[BubbleSubscription]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.SubscriptionV1)},
	Builder: func(newAction *BubbleSubscription, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Subscription = tx.account
		return nil
	},
	SingleChild: &Straw[BubbleSubscription]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.PaymentRequestMsgOp)},
		Builder: func(newAction *BubbleSubscription, bubble *Bubble) error {
			tx := bubble.Info.(BubbleTx)
			request := tx.decodedBody.Value.(abi.PaymentRequestMsgBody)
			newAction.Subscriber = tx.account
			newAction.Success = tx.success
			newAction.Amount = int64(request.Amount.Grams)
			return nil
		},
		SingleChild: &Straw[BubbleSubscription]{
			Optional:   true,
			CheckFuncs: []bubbleCheck{Is(BubbleSubscription{})},
			Builder: func(newAction *BubbleSubscription, bubble *Bubble) error {
				sub := bubble.Info.(BubbleSubscription)
				newAction.First = false
				newAction.Beneficiary = sub.Beneficiary
				newAction.Success = true
				return nil
			},
		},
	},
}
View Source
var InitialSubscriptionStraw = Straw[BubbleSubscription]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.PaymentRequestResponseMsgOp), AmountInterval(1, 1<<62)},
	Builder: func(newAction *BubbleSubscription, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Subscriber = *tx.inputFrom
		newAction.Subscription = tx.account
		newAction.Amount = tx.inputAmount
		newAction.First = len(tx.init) != 0
		return nil
	},
	SingleChild: &Straw[BubbleSubscription]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.SubscriptionPaymentMsgOp)},
		Builder: func(newAction *BubbleSubscription, bubble *Bubble) error {
			newAction.Success = true
			newAction.Beneficiary = bubble.Info.(BubbleTx).account
			return nil
		},
	},
}
View Source
var JettonBurnStraw = Straw[BubbleJettonBurn]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonBurnMsgOp)},
	Builder: func(newAction *BubbleJettonBurn, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		msg := tx.decodedBody.Value.(abi.JettonBurnMsgBody)
		newAction.amount = msg.Amount
		if tx.inputFrom != nil {
			newAction.sender = *tx.inputFrom
		}
		if tx.additionalInfo != nil {
			if master, ok := tx.additionalInfo.JettonMaster(tx.account.Address); ok {

				newAction.master = master
			}
		}
		newAction.senderWallet = tx.account.Address
		newAction.success = tx.success
		return nil
	},
	SingleChild: &Straw[BubbleJettonBurn]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonBurnNotificationMsgOp)},
		Builder: func(newAction *BubbleJettonBurn, bubble *Bubble) error {
			newAction.master = bubble.Info.(BubbleTx).account.Address
			return nil
		},
		Optional: true,
	},
}
View Source
var JettonMintStrawGovernance = Straw[BubbleJettonMint]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonMintMsgOp), HasInterface(abi.JettonMaster)},
	Builder: func(newAction *BubbleJettonMint, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		msg := tx.decodedBody.Value.(abi.JettonMintMsgBody)
		dest, err := tongo.AccountIDFromTlb(msg.ToAddress)
		if err == nil && dest != nil {
			newAction.recipient = Account{Address: *dest}
		}
		return nil
	},
	SingleChild: &Straw[BubbleJettonMint]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonInternalTransferMsgOp), HasInterface(abi.JettonWallet)},
		Builder: func(newAction *BubbleJettonMint, bubble *Bubble) error {
			tx := bubble.Info.(BubbleTx)
			msg := tx.decodedBody.Value.(abi.JettonInternalTransferMsgBody)
			newAction.amount = msg.Amount
			newAction.recipientWallet = tx.account.Address
			newAction.master = tx.inputFrom.Address
			newAction.success = tx.success
			return nil
		},
		SingleChild: &Straw[BubbleJettonMint]{
			Optional:   true,
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
		},
	},
}
View Source
var JettonTransferClassicStraw = 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.payload = body.ForwardPayload.Value
		recipient, err := ton.AccountIDFromTlb(body.Destination)
		if err == nil && recipient != nil {
			newAction.recipient = &Account{Address: *recipient}
		}
		return nil
	},
	SingleChild: &Straw[BubbleJettonTransfer]{
		CheckFuncs: []bubbleCheck{IsTx, Or(HasInterface(abi.JettonWallet), HasOperation(abi.JettonInternalTransferMsgOp))},
		Optional:   true,
		Builder: func(newAction *BubbleJettonTransfer, bubble *Bubble) error {
			tx := bubble.Info.(BubbleTx)
			newAction.recipientWallet = tx.account.Address
			if newAction.master.IsZero() {
				newAction.master, _ = tx.additionalInfo.JettonMaster(tx.account.Address)
			}
			newAction.success = tx.success
			return nil
		},
		ValueFlowUpdater: func(newAction *BubbleJettonTransfer, flow *ValueFlow) {
			if newAction.success {
				if newAction.recipient != nil {
					flow.AddJettons(newAction.recipient.Address, newAction.master, big.Int(newAction.amount))
				}
				if newAction.sender != nil {
					flow.SubJettons(newAction.sender.Address, newAction.master, big.Int(newAction.amount))
				}
			}
		},
		Children: []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
					if newAction.sender == nil {
						sender, err := ton.AccountIDFromTlb(body.Sender)
						if err == nil {
							newAction.sender = &Account{Address: *sender}
						}
					}
					return nil
				},
				ValueFlowUpdater: func(newAction *BubbleJettonTransfer, flow *ValueFlow) {
					if newAction.recipient != nil {
						flow.AddJettons(newAction.recipient.Address, newAction.master, big.Int(newAction.amount))
					}
					if newAction.sender != nil {
						flow.SubJettons(newAction.sender.Address, newAction.master, big.Int(newAction.amount))
					}
				},
				Optional: true,
			},
			{
				CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
				Optional:   true,
			},
		},
	},
}
View Source
var JettonTransferMinimalStraw = Straw[BubbleJettonTransfer]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.JettonWallet), HasOpcode(abi.JettonTransferMsgOpCode)},
	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
		return nil
	},
	SingleChild: &Straw[BubbleJettonTransfer]{
		CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.JettonWallet), HasOperation(abi.JettonInternalTransferMsgOp)},
		Optional:   true,
		Builder: func(newAction *BubbleJettonTransfer, bubble *Bubble) error {
			tx := bubble.Info.(BubbleTx)
			newAction.recipientWallet = tx.account.Address
			if newAction.master.IsZero() {
				newAction.master, _ = tx.additionalInfo.JettonMaster(tx.account.Address)
			}
			newAction.success = tx.success
			body, _ := tx.decodedBody.Value.(abi.JettonInternalTransferMsgBody)
			newAction.amount = body.Amount
			return nil
		},
		ValueFlowUpdater: func(newAction *BubbleJettonTransfer, flow *ValueFlow) {
			if newAction.success {
				if newAction.recipient != nil {
					flow.AddJettons(newAction.recipient.Address, newAction.master, big.Int(newAction.amount))
				}
				if newAction.sender != nil {
					flow.SubJettons(newAction.sender.Address, newAction.master, big.Int(newAction.amount))
				}
			}
		},
		Children: []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
					if newAction.sender == nil {
						sender, err := ton.AccountIDFromTlb(body.Sender)
						if err == nil {
							newAction.sender = &Account{Address: *sender}
						}
					}
					return nil
				},
				ValueFlowUpdater: func(newAction *BubbleJettonTransfer, flow *ValueFlow) {
					if newAction.recipient != nil {
						flow.AddJettons(newAction.recipient.Address, newAction.master, big.Int(newAction.amount))
					}
					if newAction.sender != nil {
						flow.SubJettons(newAction.sender.Address, newAction.master, big.Int(newAction.amount))
					}
				},
				Optional: true,
			},
			{
				CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
				Optional:   true,
			},
		},
	},
}
View Source
var JettonTransferPTONStraw = 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
		},
	},
}
View Source
var MegatonFiJettonSwap = Straw[BubbleJettonSwap]{
	CheckFuncs: []bubbleCheck{IsJettonTransfer, IsJettonReceiver(abi.MegatonfiRouter)},
	Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
		tx := bubble.Info.(BubbleJettonTransfer)
		newAction.UserWallet = tx.sender.Address
		newAction.In.Amount = big.Int(tx.amount)
		newAction.In.IsTon = tx.isWrappedTon
		newAction.Router = tx.recipient.Address
		newAction.In.JettonWallet = tx.senderWallet
		newAction.In.JettonMaster = tx.master
		newAction.Dex = Megatonfi
		return nil
	},
	Children: []Straw[BubbleJettonSwap]{
		{
			CheckFuncs: []bubbleCheck{IsJettonTransfer, IsJettonReceiver(abi.MegatonfiExchange)},
			Children: []Straw[BubbleJettonSwap]{
				{
					CheckFuncs: []bubbleCheck{IsJettonTransfer, IsJettonReceiver(abi.MegatonfiRouter)},
					Children: []Straw[BubbleJettonSwap]{
						{
							CheckFuncs: []bubbleCheck{IsJettonTransfer},
							Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
								tx := bubble.Info.(BubbleJettonTransfer)
								newAction.Success = tx.success
								newAction.Out.Amount = big.Int(tx.amount)
								newAction.Out.IsTon = tx.isWrappedTon
								newAction.Out.JettonWallet = tx.recipientWallet
								newAction.Out.JettonMaster = tx.master
								return nil
							},
						},
					},
				},
			},
		},
	},
}

MegatonFiJettonSwap creates a BubbleJettonSwap if there is a jetton swap in a trace.

View Source
var NftPurchaseStraw = Straw[BubbleNftPurchase]{
	CheckFuncs: []bubbleCheck{
		IsTx,
		Or(HasInterface(abi.NftSaleV2), HasInterface(abi.NftSaleV1)),
		HasEmptyBody,
		AmountInterval(1, 1<<62),
		func(bubble *Bubble) bool {
			tx := bubble.Info.(BubbleTx)
			return tx.additionalInfo != nil && tx.additionalInfo.NftSaleContract != nil && tx.additionalInfo.NftSaleContract.Owner != nil
		}},
	Builder: func(newAction *BubbleNftPurchase, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		sale := tx.additionalInfo.NftSaleContract
		newAction.Seller = *sale.Owner
		newAction.AuctionType = GetGemsAuction
		newAction.Buyer = tx.inputFrom.Address
		newAction.Price = sale.NftPrice
		if tx.additionalInfo.NftSaleContract != nil {
			newAction.Nft = tx.additionalInfo.NftSaleContract.Item
		}
		return nil
	},
	SingleChild: &Straw[BubbleNftPurchase]{
		CheckFuncs: []bubbleCheck{IsNftTransfer},
		Builder: func(newAction *BubbleNftPurchase, bubble *Bubble) error {
			newAction.Success = bubble.Info.(BubbleNftTransfer).success
			newAction.Nft = bubble.Info.(BubbleNftTransfer).account.Address
			return nil
		},
		Optional: true,
	},
}
View Source
var NftTransferNotifyStraw = Straw[BubbleNftTransfer]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.NftItem)},
	Children: []Straw[BubbleNftTransfer]{
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.NftOwnershipAssignedMsgOp)},
			Builder: func(newAction *BubbleNftTransfer, bubble *Bubble) error {
				receiverTx := bubble.Info.(BubbleTx)
				transfer := receiverTx.decodedBody.Value.(abi.NftOwnershipAssignedMsgBody)
				newAction.success = true
				if receiverTx.inputFrom == nil {
					return fmt.Errorf("nft transfer notify without sender")
				}
				newAction.account = *receiverTx.inputFrom
				newAction.recipient = &receiverTx.account
				newAction.payload = transfer.ForwardPayload.Value
				return nil
			},
		},
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
			Optional:   true,
		},
	},
}
View Source
var NftTransferStraw = Straw[BubbleNftTransfer]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.NftTransferMsgOp), HasInterface(abi.NftItem)},
	Builder: func(newAction *BubbleNftTransfer, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		transfer := tx.decodedBody.Value.(abi.NftTransferMsgBody)
		newAction.account = tx.account
		newAction.success = tx.success
		newAction.sender = tx.inputFrom
		newAction.payload = transfer.ForwardPayload.Value
		if newAction.recipient == nil {
			newAction.recipient = parseAccount(transfer.NewOwner)
		}
		return nil
	},
	Children: []Straw[BubbleNftTransfer]{
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.NftOwnershipAssignedMsgOp)},
			Optional:   true,
			Builder: func(newAction *BubbleNftTransfer, bubble *Bubble) error {
				receiverTx := bubble.Info.(BubbleTx)
				transfer := receiverTx.decodedBody.Value.(abi.NftOwnershipAssignedMsgBody)
				newAction.success = true
				newAction.payload = transfer.ForwardPayload.Value
				return nil
			},
		},
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
			Optional:   true,
		},
	},
}
View Source
var PendingWithdrawRequestLiquidStraw = Straw[BubbleWithdrawStakeRequest]{
	CheckFuncs: []bubbleCheck{Is(BubbleJettonBurn{})},
	Builder: func(newAction *BubbleWithdrawStakeRequest, bubble *Bubble) error {
		newAction.Staker = bubble.Info.(BubbleJettonBurn).sender.Address
		newAction.Success = true
		newAction.Implementation = core.StakingImplementationLiquidTF
		amount := big.Int(bubble.Info.(BubbleJettonBurn).amount)
		i := amount.Int64()
		newAction.Amount = &i
		return nil
	},
	SingleChild: &Straw[BubbleWithdrawStakeRequest]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.TonstakePoolWithdrawMsgOp)},
		Builder: func(newAction *BubbleWithdrawStakeRequest, bubble *Bubble) error {
			newAction.Pool = bubble.Info.(BubbleTx).account.Address
			newAction.Success = true
			newAction.attachedAmount = bubble.Info.(BubbleTx).inputAmount
			return nil
		},
		SingleChild: &Straw[BubbleWithdrawStakeRequest]{
			Optional:   true,
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.TonstakePayoutMintJettonsMsgOp)},
			SingleChild: &Straw[BubbleWithdrawStakeRequest]{
				CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.TonstakeNftInitMsgOp)},
				SingleChild: &Straw[BubbleWithdrawStakeRequest]{
					CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.NftOwnershipAssignedMsgOp)},
					Builder: func(newAction *BubbleWithdrawStakeRequest, bubble *Bubble) error {
						newAction.Success = true
						return nil
					},
				},
			},
		},
	},
}
View Source
var StonfiMintStraw = Straw[BubbleJettonMint]{}

https://dev.tonviewer.com/transaction/e19381edd8f05922eeba3c31f4b8b4b737478b4ca7b37130bdbbfd7bfa773227 todo: add liquidity (mint lp tokens)

View Source
var StonfiSwapStraw = 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.StonfiSwapJettonOp {
			return false
		}
		swap, ok := jettonTx.payload.Value.(abi.StonfiSwapJettonPayload)
		if !ok {
			return false
		}
		to, err := ton.AccountIDFromTlb(swap.ToAddress)
		if err != nil || to == nil {
			return false
		}
		if jettonTx.sender.Address != *to {
			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.StonfiSwapMsgOp), HasInterface(abi.StonfiPool)},
		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.StonfiSwapMsgBody)
			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.StonfiPaymentRequestMsgOp)},
			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{}), Or(JettonTransferOpCode(0xc64370e5), JettonTransferOpCode(0x5ffe1295))},
				Builder: func(newAction *BubbleJettonSwap, bubble *Bubble) error {
					jettonTx := bubble.Info.(BubbleJettonTransfer)
					if jettonTx.senderWallet != newAction.Out.JettonWallet {

						return nil
					}
					newAction.Out.Amount = big.Int(jettonTx.amount)
					newAction.Out.IsTon = jettonTx.isWrappedTon
					newAction.Success = true
					return nil
				},
			},
		},
	},
}
View Source
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 {
			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), func(bubble *Bubble) bool {
			tx, ok := bubble.Info.(BubbleTx)
			if !ok {
				return false
			}
			if tx.additionalInfo.STONfiPool == nil {
				return false
			}
			return true
		}},
		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
			}
			s, err := tongo.AccountIDFromTlb(body.DexPayload.TokenWallet1)
			if err != nil {
				return err
			}
			if s != nil && *s == a {
				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
		},
		Children: []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 {

							return nil
						}
						newAction.Out.Amount = big.Int(jettonTx.amount)
						newAction.Out.IsTon = jettonTx.isWrappedTon
						newAction.Success = true
						return nil
					},
				},
			},
			{
				CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.StonfiPayVaultV2MsgOp)},
				Optional:   true,
				SingleChild: &Straw[BubbleJettonSwap]{
					CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.StonfiDepositRefFeeV2MsgOp)},
					SingleChild: &Straw[BubbleJettonSwap]{
						CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
						Optional:   true,
					},
				},
			},
		},
	},
}
View Source
var StonfiV2PTONStraw = Straw[BubbleJettonTransfer]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.JettonWallet), HasOperation(abi.PtonTonTransferMsgOp)},
	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.PtonTonTransferMsgBody)
		newAction.amount = tlb.VarUInteger16(*big.NewInt(int64(body.TonAmount)))
		newAction.isWrappedTon = true
		recipient, err := ton.AccountIDFromTlb(body.RefundAddress)
		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
		},
	},
}
View Source
var StrawAuctionBigGetgems = Straw[AuctionBidBubble]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.NftAuctionV1), HasEmptyBody, AmountInterval(1, 1<<62)},
	Builder: func(newAction *AuctionBidBubble, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Auction = tx.account.Address
		newAction.Bidder = tx.inputFrom.Address
		newAction.Amount = tx.inputAmount
		newAction.Success = tx.success
		newAction.Type = GetGemsAuction
		if tx.additionalInfo != nil && tx.additionalInfo.NftSaleContract != nil {
			newAction.NftAddress = &tx.additionalInfo.NftSaleContract.Item
		}
		return nil
	},
}
View Source
var StrawAuctionBuyFragments = Straw[BubbleNftPurchase]{
	CheckFuncs: []bubbleCheck{Is(AuctionBidBubble{})},
	Builder: func(newAction *BubbleNftPurchase, bubble *Bubble) error {
		bid := bubble.Info.(AuctionBidBubble)
		newAction.Buyer = bid.Bidder
		newAction.Nft = *bid.NftAddress
		newAction.Price = bid.Amount
		newAction.AuctionType = bid.Type
		newAction.Success = bid.Success
		return nil
	},
	SingleChild: &Straw[BubbleNftPurchase]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.NftOwnershipAssignedMsgOp)},
		Builder: func(newAction *BubbleNftPurchase, bubble *Bubble) error {
			newAction.Seller = parseAccount(bubble.Info.(BubbleTx).decodedBody.Value.(abi.NftOwnershipAssignedMsgBody).PrevOwner).Address
			return nil
		},
	},
}
View Source
var StrawAuctionBuyGetgems = Straw[BubbleNftPurchase]{
	CheckFuncs: []bubbleCheck{Is(AuctionBidBubble{})},
	Builder: func(newAction *BubbleNftPurchase, bubble *Bubble) error {
		bid := bubble.Info.(AuctionBidBubble)
		newAction.Buyer = bid.Bidder
		newAction.Nft = *bid.NftAddress
		newAction.Price = bid.Amount
		newAction.AuctionType = bid.Type
		newAction.Success = bid.Success
		return nil
	},
	SingleChild: &Straw[BubbleNftPurchase]{
		CheckFuncs: []bubbleCheck{IsNftTransfer},
	},
}
View Source
var StrawFindAuctionBidFragmentSimple = Straw[AuctionBidBubble]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.Teleitem), HasEmptyBody, AmountInterval(1, 1<<62)},
	Builder: func(newAction *AuctionBidBubble, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Type = DnsTgAuction
		newAction.Amount = tx.inputAmount
		newAction.Bidder = tx.inputFrom.Address
		newAction.Success = tx.success
		newAction.Auction = tx.account.Address
		newAction.NftAddress = &tx.account.Address
		return nil
	},
}
View Source
var TgAuctionV1InitialBidStraw = Straw[AuctionBidBubble]{
	CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.TelemintDeployMsgOp)},
	Builder: func(newAction *AuctionBidBubble, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		body := tx.decodedBody.Value.(abi.TelemintDeployMsgBody)
		newAction.Type = DnsTgAuction
		newAction.Amount = tx.inputAmount
		newAction.Bidder = tx.inputFrom.Address
		newAction.Username = string(body.Msg.Username)
		return nil
	},
	SingleChild: &Straw[AuctionBidBubble]{
		CheckFuncs: []bubbleCheck{IsTx, HasOpcode(0x299a3e15)},
		Builder: func(newAction *AuctionBidBubble, bubble *Bubble) error {
			tx := bubble.Info.(BubbleTx)
			newAction.Success = tx.success

			newAction.Auction = tx.account.Address
			newAction.NftAddress = &tx.account.Address
			if tx.additionalInfo.EmulatedTeleitemNFT != nil {
				newAction.Nft = &core.NftItem{
					Address:           tx.account.Address,
					Index:             tx.additionalInfo.EmulatedTeleitemNFT.Index,
					CollectionAddress: tx.additionalInfo.EmulatedTeleitemNFT.CollectionAddress,
					Verified:          tx.additionalInfo.EmulatedTeleitemNFT.Verified,
					Transferable:      false,
					Metadata: map[string]interface{}{
						"name":  newAction.Username,
						"image": fmt.Sprintf("https://nft.fragment.com/username/%v.webp", newAction.Username),
					},
				}
			}
			return nil
		},
	},
}
View Source
var UnSubscriptionStraw = Straw[BubbleUnSubscription]{
	CheckFuncs: []bubbleCheck{IsTx},
	Builder: func(newAction *BubbleUnSubscription, bubble *Bubble) error {
		newAction.Subscriber = bubble.Info.(BubbleTx).account
		return nil
	},
	SingleChild: &Straw[BubbleUnSubscription]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.WalletPluginDestructMsgOp)},
		Builder: func(newAction *BubbleUnSubscription, bubble *Bubble) error {
			tx := bubble.Info.(BubbleTx)
			newAction.Subscription = tx.account
			newAction.Success = tx.success
			return nil
		},
		SingleChild: &Straw[BubbleUnSubscription]{
			Optional:   true,
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.WalletPluginDestructMsgOp)},
			Builder: func(newAction *BubbleUnSubscription, bubble *Bubble) error {
				newAction.Beneficiary = bubble.Info.(BubbleTx).account
				return nil
			},
		},
	},
}
View Source
var WithdrawLiquidStake = Straw[BubbleWithdrawStake]{
	CheckFuncs: []bubbleCheck{Is(BubbleWithdrawStakeRequest{})},
	Builder: func(newAction *BubbleWithdrawStake, bubble *Bubble) error {
		request := bubble.Info.(BubbleWithdrawStakeRequest)
		newAction.Amount -= request.attachedAmount
		newAction.Pool = request.Pool
		newAction.Staker = request.Staker
		newAction.Implementation = request.Implementation
		return nil
	},
	SingleChild: &Straw[BubbleWithdrawStake]{
		CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.TonstakePoolWithdrawalMsgOp)},
		Builder: func(newAction *BubbleWithdrawStake, bubble *Bubble) error {
			newAction.Amount += bubble.Info.(BubbleTx).inputAmount
			return nil
		},
	},
}
View Source
var WithdrawStakeImmediatelyStraw = Straw[BubbleWithdrawStake]{
	CheckFuncs: []bubbleCheck{Is(BubbleWithdrawStakeRequest{})},
	Builder: func(newAction *BubbleWithdrawStake, bubble *Bubble) error {
		req := bubble.Info.(BubbleWithdrawStakeRequest)
		newAction.Pool = req.Pool
		newAction.Staker = req.Staker
		newAction.Amount = -req.attachedAmount
		newAction.Implementation = req.Implementation
		return nil
	},
	SingleChild: &Straw[BubbleWithdrawStake]{
		CheckFuncs: []bubbleCheck{IsTx, AmountInterval(int64(ton.OneTON), 1<<63-1)},
		Builder: func(newAction *BubbleWithdrawStake, bubble *Bubble) error {
			newAction.Amount += bubble.Info.(BubbleTx).inputAmount
			return nil
		},
	},
}
View Source
var WithdrawTFStakeRequestStraw = Straw[BubbleWithdrawStakeRequest]{
	CheckFuncs: []bubbleCheck{IsTx, HasInterface(abi.TvPool), HasTextComment("w")},
	Builder: func(newAction *BubbleWithdrawStakeRequest, bubble *Bubble) error {
		tx := bubble.Info.(BubbleTx)
		newAction.Pool = tx.account.Address
		newAction.Staker = tx.inputFrom.Address
		newAction.Success = tx.success
		newAction.attachedAmount = tx.inputAmount
		newAction.Implementation = core.StakingImplementationTF
		return nil
	},
	Children: []Straw[BubbleWithdrawStakeRequest]{
		{
			Optional:   true,
			CheckFuncs: []bubbleCheck{IsTx, AmountInterval(0, int64(ton.OneTON))},
		},
	},
}
View Source
var WtonMintStraw = Straw[BubbleJettonMint]{
	CheckFuncs: []bubbleCheck{IsTx, HasOpcode(0x77a33521)},
	Builder: func(newAction *BubbleJettonMint, bubble *Bubble) error {
		newAction.recipient = bubble.Info.(BubbleTx).account
		return nil
	},
	Children: []Straw[BubbleJettonMint]{
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonInternalTransferMsgOp)},
			Builder: func(newAction *BubbleJettonMint, bubble *Bubble) error {
				tx := bubble.Info.(BubbleTx)
				body := tx.decodedBody.Value.(abi.JettonInternalTransferMsgBody)
				newAction.amount = body.Amount
				if tx.additionalInfo != nil {
					if master, ok := tx.additionalInfo.JettonMaster(tx.account.Address); ok {
						newAction.master = master
					}
				}
				newAction.recipientWallet = tx.account.Address
				newAction.success = tx.success
				return nil
			},
			Children: []Straw[BubbleJettonMint]{
				{
					CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.JettonNotifyMsgOp)},
					Optional:   true,
				},
				{
					CheckFuncs: []bubbleCheck{Is(BubbleContractDeploy{})},
					Optional:   true,
				},
			},
		},
		{
			CheckFuncs: []bubbleCheck{IsTx, HasOperation(abi.ExcessMsgOp)},
			Optional:   true,
		},
	},
}

Functions

func AmountInterval

func AmountInterval(min, max int64) bubbleCheck

func CollectActionsAndValueFlow

func CollectActionsAndValueFlow(bubble *Bubble, forAccount *tongo.AccountID) ([]Action, *ValueFlow)

func ConvertToInscriptionActions

func ConvertToInscriptionActions(msgs []core.InscriptionMessage) map[ton.Bits256][]Action

func HasEmptyBody

func HasEmptyBody(b *Bubble) bool

func HasInterface

func HasInterface(iface abi.ContractInterface) bubbleCheck

func HasOpcode

func HasOpcode(op uint32) bubbleCheck

func HasOperation

func HasOperation(name abi.MsgOpName) bubbleCheck

func HasTextComment

func HasTextComment(comment string) bubbleCheck

func Is

func Is(t actioner) bubbleCheck

func IsAccount

func IsAccount(id tongo.AccountID) bubbleCheck

func IsBounced

func IsBounced(bubble *Bubble) bool

func IsJettonReceiver

func IsJettonReceiver(iface abi.ContractInterface) bubbleCheck

func IsJettonTransfer

func IsJettonTransfer(b *Bubble) bool

func IsNftTransfer

func IsNftTransfer(b *Bubble) bool

func IsTx

func IsTx(b *Bubble) bool

func JettonTransferOpCode

func JettonTransferOpCode(opCode uint32) bubbleCheck

func JettonTransferOperation

func JettonTransferOperation(op abi.JettonOpName) bubbleCheck

func MergeAllBubbles

func MergeAllBubbles(bubble *Bubble, straws []Merger)

func Or

func Or(check1, check2 bubbleCheck) bubbleCheck

Types

type Account

type Account struct {
	Address    tongo.AccountID
	Interfaces []abi.ContractInterface
}

func (*Account) Addr

func (a *Account) Addr() *tongo.AccountID

func (Account) Is

type AccountValueFlow

type AccountValueFlow struct {
	Ton     int64
	Fees    int64
	Jettons map[tongo.AccountID]big.Int
	NFTs    [2]int // 0 - added, 1 - removed
}

AccountValueFlow contains a change of assets for a particular account.

type Action

type Action struct {
	TonTransfer           *TonTransferAction           `json:",omitempty"`
	SmartContractExec     *SmartContractAction         `json:",omitempty"`
	NftItemTransfer       *NftTransferAction           `json:",omitempty"`
	NftPurchase           *NftPurchaseAction           `json:",omitempty"`
	JettonTransfer        *JettonTransferAction        `json:",omitempty"`
	JettonMint            *JettonMintAction            `json:",omitempty"`
	JettonBurn            *JettonBurnAction            `json:",omitempty"`
	ContractDeploy        *ContractDeployAction        `json:",omitempty"`
	Subscription          *SubscriptionAction          `json:",omitempty"`
	UnSubscription        *UnSubscriptionAction        `json:",omitempty"`
	AuctionBid            *AuctionBidAction            `json:",omitempty"`
	ElectionsDepositStake *ElectionsDepositStakeAction `json:",omitempty"`
	ElectionsRecoverStake *ElectionsRecoverStakeAction `json:",omitempty"`
	DepositStake          *DepositStakeAction          `json:",omitempty"`
	WithdrawStake         *WithdrawStakeAction         `json:",omitempty"`
	WithdrawStakeRequest  *WithdrawStakeRequestAction  `json:",omitempty"`
	JettonSwap            *JettonSwapAction            `json:",omitempty"`
	DnsRenew              *DnsRenewAction              `json:",omitempty"`
	InscriptionMint       *InscriptionMintAction       `json:",omitempty"`
	InscriptionTransfer   *InscriptionTransferAction   `json:",omitempty"`
	Success               bool
	Type                  ActionType
	Error                 *string `json:",omitempty"`
	BaseTransactions      []ton.Bits256
}

func (Action) ContributeToExtra

func (a Action) ContributeToExtra(account tongo.AccountID) int64

func (Action) IsSubject

func (a Action) IsSubject(account tongo.AccountID) bool

func (Action) String

func (a Action) String() string

type ActionType

type ActionType string

type ActionsList

type ActionsList struct {
	Actions   []Action
	ValueFlow *ValueFlow
}

func EnrichWithIntentions

func EnrichWithIntentions(trace *core.Trace, actions *ActionsList) *ActionsList

func FindActions

func FindActions(ctx context.Context, trace *core.Trace, opts ...Option) (*ActionsList, error)

FindActions finds known action patterns in the given trace and returns a list of actions.

func (*ActionsList) Extra

func (l *ActionsList) Extra(account tongo.AccountID) int64

type AuctionBidAction

type AuctionBidAction struct {
	Type       NftAuctionType
	Amount     int64
	Nft        *core.NftItem
	NftAddress *tongo.AccountID
	Bidder     tongo.AccountID
	Auction    tongo.AccountID
}

func (*AuctionBidAction) SubjectAccounts

func (a *AuctionBidAction) SubjectAccounts() []tongo.AccountID

type AuctionBidBubble

type AuctionBidBubble struct {
	Type           NftAuctionType
	Amount         int64
	Nft            *core.NftItem
	NftAddress     *tongo.AccountID
	Bidder         tongo.AccountID
	Auction        tongo.AccountID
	PreviousBidder *tongo.AccountID //maybe don't requered
	Username       string
	Success        bool
}

func (AuctionBidBubble) ToAction

func (a AuctionBidBubble) ToAction() *Action

type Bubble

type Bubble struct {
	Info        actioner
	Accounts    []tongo.AccountID
	Children    []*Bubble
	ValueFlow   *ValueFlow
	Transaction []ton.Bits256
}

Bubble represents a transaction in the beginning. But we can merge neighbour bubbles together if we find a known action pattern like an NFT Transfer or a SmartContractExecution in a trace.

func FromTrace

func FromTrace(trace *core.Trace) *Bubble

func ProcessChildren

func ProcessChildren(children []*Bubble, fns ...func(child *Bubble) *Merge) []*Bubble

func (Bubble) String

func (b Bubble) String() string

type BubbleContractDeploy

type BubbleContractDeploy struct {
	Contract tongo.AccountID
	// AccountInitInterfaces is a list of interfaces implemented by the stateInit.Code.
	// This list can differ from the current list of interfaces.
	// TODO: AccountInitInterfaces is an empty list in opentonapi, fix.
	AccountInitInterfaces []abi.ContractInterface
	Success               bool
}

func (BubbleContractDeploy) ToAction

func (b BubbleContractDeploy) ToAction() *Action

type BubbleDepositStake

type BubbleDepositStake struct {
	Staker         tongo.AccountID
	Amount         int64
	Success        bool
	Pool           tongo.AccountID
	Implementation core.StakingImplementation
}

func (BubbleDepositStake) ToAction

func (ds BubbleDepositStake) ToAction() *Action

type BubbleDnsItemRenew

type BubbleDnsItemRenew struct {
	DnsRenewAction
	Success bool
}

func (BubbleDnsItemRenew) ToAction

func (b BubbleDnsItemRenew) ToAction() *Action

type BubbleElectionsDepositStake

type BubbleElectionsDepositStake struct {
	Staker  tongo.AccountID
	Amount  int64
	Success bool
}

func (BubbleElectionsDepositStake) ToAction

func (ds BubbleElectionsDepositStake) ToAction() *Action

type BubbleElectionsRecoverStake

type BubbleElectionsRecoverStake struct {
	Staker  tongo.AccountID
	Amount  int64
	Success bool
}

func (BubbleElectionsRecoverStake) ToAction

func (b BubbleElectionsRecoverStake) ToAction() *Action

type BubbleJettonBurn

type BubbleJettonBurn struct {
	// contains filtered or unexported fields
}

func (BubbleJettonBurn) ToAction

func (b BubbleJettonBurn) ToAction() (action *Action)

type BubbleJettonMint

type BubbleJettonMint struct {
	// contains filtered or unexported fields
}

func (BubbleJettonMint) ToAction

func (b BubbleJettonMint) ToAction() (action *Action)

type BubbleJettonSwap

type BubbleJettonSwap struct {
	Dex        Dex
	UserWallet tongo.AccountID
	Router     tongo.AccountID
	Out        assetTransfer
	In         assetTransfer
	Success    bool
}

BubbleJettonSwap contains information about a jetton swap operation at a dex.

func (BubbleJettonSwap) ToAction

func (b BubbleJettonSwap) ToAction() *Action

type BubbleJettonTransfer

type BubbleJettonTransfer struct {
	// contains filtered or unexported fields
}

func (BubbleJettonTransfer) ToAction

func (b BubbleJettonTransfer) ToAction() (action *Action)

type BubbleNftPurchase

type BubbleNftPurchase struct {
	Success     bool
	Buyer       tongo.AccountID
	Seller      tongo.AccountID
	Nft         tongo.AccountID
	AuctionType NftAuctionType
	Price       int64
}

func (BubbleNftPurchase) ToAction

func (b BubbleNftPurchase) ToAction() *Action

type BubbleNftTransfer

type BubbleNftTransfer struct {
	// contains filtered or unexported fields
}

func (BubbleNftTransfer) ToAction

func (b BubbleNftTransfer) ToAction() (action *Action)

type BubbleSubscription

type BubbleSubscription struct {
	Subscription, Subscriber, Beneficiary Account
	Amount                                int64
	Success                               bool
	First                                 bool
}

func (BubbleSubscription) ToAction

func (b BubbleSubscription) ToAction() (action *Action)

type BubbleTx

type BubbleTx struct {
	// contains filtered or unexported fields
}

func (BubbleTx) String

func (b BubbleTx) String() string

func (BubbleTx) ToAction

func (b BubbleTx) ToAction() *Action

type BubbleUnSubscription

type BubbleUnSubscription struct {
	Subscription, Subscriber, Beneficiary Account
	Success                               bool
}

func (BubbleUnSubscription) ToAction

func (b BubbleUnSubscription) ToAction() (action *Action)

type BubbleWithdrawStake

type BubbleWithdrawStake struct {
	Staker         tongo.AccountID
	Amount         int64
	Pool           tongo.AccountID
	Implementation core.StakingImplementation
}

func (BubbleWithdrawStake) ToAction

func (ds BubbleWithdrawStake) ToAction() *Action

type BubbleWithdrawStakeRequest

type BubbleWithdrawStakeRequest struct {
	Staker         tongo.AccountID
	Amount         *int64
	Success        bool
	Pool           tongo.AccountID
	Implementation core.StakingImplementation
	// contains filtered or unexported fields
}

func (BubbleWithdrawStakeRequest) ToAction

func (ds BubbleWithdrawStakeRequest) ToAction() *Action

type ContractDeployAction

type ContractDeployAction struct {
	Address    tongo.AccountID
	Interfaces []abi.ContractInterface
}

func (*ContractDeployAction) SubjectAccounts

func (a *ContractDeployAction) SubjectAccounts() []tongo.AccountID

type ContractDeployment

type ContractDeployment struct {
	// contains filtered or unexported fields
}

ContractDeployment holds information about initialization of a contract.

type DepositStakeAction

type DepositStakeAction struct {
	Staker         tongo.AccountID
	Amount         int64
	Pool           tongo.AccountID
	Implementation core.StakingImplementation
}

func (*DepositStakeAction) SubjectAccounts

func (a *DepositStakeAction) SubjectAccounts() []tongo.AccountID

type Dex

type Dex string
const (
	Stonfi    Dex = "stonfi"
	Megatonfi Dex = "megatonfi"
	Dedust    Dex = "dedust"
)

type DnsRenewAction

type DnsRenewAction struct {
	Item    ton.AccountID
	Renewer ton.AccountID
}

func (DnsRenewAction) SubjectAccounts

func (a DnsRenewAction) SubjectAccounts() []ton.AccountID

type ElectionsDepositStakeAction

type ElectionsDepositStakeAction struct {
	Amount  int64
	Elector tongo.AccountID
	Staker  tongo.AccountID
}

func (*ElectionsDepositStakeAction) SubjectAccounts

func (a *ElectionsDepositStakeAction) SubjectAccounts() []tongo.AccountID

type ElectionsRecoverStakeAction

type ElectionsRecoverStakeAction struct {
	Amount  int64
	Elector tongo.AccountID
	Staker  tongo.AccountID
}

func (*ElectionsRecoverStakeAction) SubjectAccounts

func (a *ElectionsRecoverStakeAction) SubjectAccounts() []tongo.AccountID

type EncryptedComment

type EncryptedComment struct {
	EncryptionType string
	CipherText     []byte
}

type InscriptionMintAction

type InscriptionMintAction struct {
	Minter ton.AccountID
	Amount uint64
	Ticker string
	Type   string
}

type InscriptionTransferAction

type InscriptionTransferAction struct {
	Src, Dst ton.AccountID
	Amount   uint64
	Ticker   string
	Type     string
}

type JettonBurnAction

type JettonBurnAction struct {
	Jetton        tongo.AccountID
	Sender        tongo.AccountID
	SendersWallet tongo.AccountID
	Amount        tlb.VarUInteger16
}

func (*JettonBurnAction) SubjectAccounts

func (a *JettonBurnAction) SubjectAccounts() []tongo.AccountID

type JettonMintAction

type JettonMintAction struct {
	Jetton           tongo.AccountID
	Recipient        tongo.AccountID
	RecipientsWallet tongo.AccountID
	Amount           tlb.VarUInteger16
}

func (*JettonMintAction) SubjectAccounts

func (a *JettonMintAction) SubjectAccounts() []tongo.AccountID

type JettonSwapAction

type JettonSwapAction struct {
	Dex        Dex
	UserWallet tongo.AccountID
	Router     tongo.AccountID
	In         assetTransfer
	Out        assetTransfer
}

func (*JettonSwapAction) SubjectAccounts

func (a *JettonSwapAction) SubjectAccounts() []tongo.AccountID

type JettonTransferAction

type JettonTransferAction struct {
	Comment          *string
	EncryptedComment *EncryptedComment
	Jetton           tongo.AccountID
	Recipient        *tongo.AccountID
	Sender           *tongo.AccountID
	RecipientsWallet tongo.AccountID
	SendersWallet    tongo.AccountID
	Amount           tlb.VarUInteger16
	Refund           *Refund
	// contains filtered or unexported fields
}

func (*JettonTransferAction) SubjectAccounts

func (a *JettonTransferAction) SubjectAccounts() []tongo.AccountID

type Merge

type Merge struct {
	// contains filtered or unexported fields
}

type Merger

type Merger interface {
	// Merge extracts information from the given bubble and its children and modifies the bubble if needed.
	// If the bubble is modified this function return true.
	Merge(bubble *Bubble) (success bool)
}

type NftAuctionType

type NftAuctionType string

type NftPurchaseAction

type NftPurchaseAction struct {
	Nft         tongo.AccountID
	Buyer       tongo.AccountID
	Seller      tongo.AccountID
	AuctionType NftAuctionType
	Price       int64
}

func (*NftPurchaseAction) SubjectAccounts

func (a *NftPurchaseAction) SubjectAccounts() []tongo.AccountID

type NftTransferAction

type NftTransferAction struct {
	Comment          *string
	EncryptedComment *EncryptedComment
	Recipient        *tongo.AccountID
	Sender           *tongo.AccountID
	Nft              tongo.AccountID
	Refund           *Refund
}

func (*NftTransferAction) SubjectAccounts

func (a *NftTransferAction) SubjectAccounts() []tongo.AccountID

type Option

type Option func(*Options)

func ForAccount

func ForAccount(a tongo.AccountID) Option

func WithInformationSource

func WithInformationSource(source core.InformationSource) Option

func WithStraws

func WithStraws(straws []Merger) Option

WithStraws provides functions to find actions in a trace.

type Options

type Options struct {
	// contains filtered or unexported fields
}

type OutMessage

type OutMessage struct {
	// contains filtered or unexported fields
}

type Refund

type Refund struct {
	Type   RefundType
	Origin string
}

type RefundType

type RefundType string

type SmartContractAction

type SmartContractAction struct {
	TonAttached int64
	Executor    tongo.AccountID
	Contract    tongo.AccountID
	Operation   string
	Payload     string
}

func (*SmartContractAction) SubjectAccounts

func (a *SmartContractAction) SubjectAccounts() []tongo.AccountID

type Straw

type Straw[newBubbleT actioner] struct {
	CheckFuncs       []bubbleCheck
	Builder          func(newAction *newBubbleT, bubble *Bubble) error //uses to convert old bubble to new Bubble.Info
	ValueFlowUpdater func(newAction *newBubbleT, flow *ValueFlow)
	SingleChild      *Straw[newBubbleT]
	Children         []Straw[newBubbleT]
	Optional         bool
}

func Optional

func Optional[T actioner](s Straw[T]) Straw[T]

Optional returns copy of declarative straw but optional

func (Straw[newBubbleT]) Merge

func (s Straw[newBubbleT]) Merge(bubble *Bubble) bool

type SubscriptionAction

type SubscriptionAction struct {
	Subscription tongo.AccountID
	Subscriber   tongo.AccountID
	Beneficiary  tongo.AccountID
	Amount       int64
	First        bool
}

func (*SubscriptionAction) SubjectAccounts

func (a *SubscriptionAction) SubjectAccounts() []tongo.AccountID

type TonTransferAction

type TonTransferAction struct {
	Amount           int64
	Comment          *string
	EncryptedComment *EncryptedComment
	Recipient        tongo.AccountID
	Sender           tongo.AccountID
	Refund           *Refund
}

func (*TonTransferAction) SubjectAccounts

func (a *TonTransferAction) SubjectAccounts() []tongo.AccountID

type UnSubscriptionAction

type UnSubscriptionAction struct {
	Subscription tongo.AccountID
	Subscriber   tongo.AccountID
	Beneficiary  tongo.AccountID
}

func (*UnSubscriptionAction) SubjectAccounts

func (a *UnSubscriptionAction) SubjectAccounts() []tongo.AccountID

type ValueFlow

type ValueFlow struct {
	Accounts map[tongo.AccountID]*AccountValueFlow
}

ValueFlow contains a change of assets for each account involved in a trace.

func (*ValueFlow) AddFee

func (flow *ValueFlow) AddFee(accountID tongo.AccountID, amount int64)

func (*ValueFlow) AddJettons

func (flow *ValueFlow) AddJettons(accountID tongo.AccountID, jettonMaster tongo.AccountID, value big.Int)

func (*ValueFlow) AddTons

func (flow *ValueFlow) AddTons(accountID tongo.AccountID, amount int64)

func (*ValueFlow) Merge

func (flow *ValueFlow) Merge(other *ValueFlow)

func (*ValueFlow) SubJettons

func (flow *ValueFlow) SubJettons(accountID tongo.AccountID, jettonMaster tongo.AccountID, value big.Int)

type WithdrawStakeAction

type WithdrawStakeAction struct {
	Staker         tongo.AccountID
	Amount         int64
	Pool           tongo.AccountID
	Implementation core.StakingImplementation
}

func (*WithdrawStakeAction) SubjectAccounts

func (a *WithdrawStakeAction) SubjectAccounts() []tongo.AccountID

type WithdrawStakeRequestAction

type WithdrawStakeRequestAction struct {
	Staker         tongo.AccountID
	Amount         *int64
	Pool           tongo.AccountID
	Implementation core.StakingImplementation
}

func (*WithdrawStakeRequestAction) SubjectAccounts

func (a *WithdrawStakeRequestAction) SubjectAccounts() []tongo.AccountID

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL