Skip to content

Commit

Permalink
Jetton accept example & address Equals func
Browse files Browse the repository at this point in the history
  • Loading branch information
xssnick committed Jul 12, 2024
1 parent 09eedeb commit 98d6ede
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 9 deletions.
5 changes: 5 additions & 0 deletions address/addr.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package address

import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/hex"
Expand Down Expand Up @@ -337,3 +338,7 @@ func (a *Address) Workchain() int32 {
func (a *Address) Data() []byte {
return a.data
}

func (a *Address) Equals(b *Address) bool {
return a.workchain == b.workchain && bytes.Equal(a.data, b.data)
}
39 changes: 33 additions & 6 deletions example/accept-payments/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/xssnick/tonutils-go/liteclient"
"github.com/xssnick/tonutils-go/tlb"
"github.com/xssnick/tonutils-go/ton"
"github.com/xssnick/tonutils-go/ton/jetton"
"log"
)

Expand All @@ -26,19 +27,17 @@ func main() {
}

// initialize ton api lite connection wrapper with full proof checks
api := ton.NewAPIClient(client, ton.ProofCheckPolicySecure).WithRetry()
api := ton.NewAPIClient(client, ton.ProofCheckPolicyFast).WithRetry()
api.SetTrustedBlockFromConfig(cfg)

log.Println("fetching and checking proofs since config init block, it may take near a minute...")
master, err := api.CurrentMasterchainInfo(context.Background()) // we fetch block just to trigger chain proof check
if err != nil {
log.Fatalln("get masterchain info err: ", err.Error())
return
}
log.Println("master proof checks are completed successfully, now communication is 100% safe!")

// address on which we are accepting payments
treasuryAddress := address.MustParseAddr("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N")
treasuryAddress := address.MustParseAddr("EQAYqo4u7VF0fa4DPAebk4g9lBytj2VFny7pzXR0trjtXQaO")

acc, err := api.GetAccount(context.Background(), master, treasuryAddress)
if err != nil {
Expand All @@ -58,10 +57,38 @@ func main() {

log.Println("waiting for transfers...")

// USDT master contract addr, but can be any jetton
usdt := jetton.NewJettonMasterClient(api, address.MustParseAddr("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"))
// get our jetton wallet address
treasuryJettonWallet, err := usdt.GetJettonWalletAtBlock(context.Background(), treasuryAddress, master)
if err != nil {
log.Fatalln("get jetton wallet address err: ", err.Error())
return
}

// listen for new transactions from channel
for tx := range transactions {
// process transaction here
log.Println(tx.String())
// only internal messages can increase the balance
if tx.IO.In != nil && tx.IO.In.MsgType == tlb.MsgTypeInternal {
ti := tx.IO.In.AsInternal()
src := ti.SrcAddr

// verify that sender is our jetton wallet
if ti.SrcAddr.Equals(treasuryJettonWallet.Address()) {
var transfer jetton.TransferNotification
if err = tlb.LoadFromCell(&transfer, ti.Body.BeginParse()); err == nil {
// convert decimals to 6 for USDT (it can be fetched from jetton details too), default is 9
amt := tlb.MustFromNano(transfer.Amount.Nano(), 6)

// reassign sender to real jetton sender instead of its jetton wallet contract
src = transfer.Sender
log.Println("received", amt.String(), "USDT from", src.String())
}
}

// show received ton amount
log.Println("received", ti.Amount.String(), "TON from", src.String())
}

// update last processed lt and save it in db
lastProcessedLT = tx.LT
Expand Down
10 changes: 7 additions & 3 deletions tlb/transaction.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tlb

import (
"encoding/hex"
"fmt"
"math/big"
"reflect"
Expand Down Expand Up @@ -290,17 +291,20 @@ func (t *Transaction) String() string {
case TransactionDescriptionOrdinary:
}
if t.IO.In != nil {
build += fmt.Sprintf("LT: %d", t.LT)

if t.IO.In.MsgType == MsgTypeInternal {
in = t.IO.In.AsInternal().Amount.Nano()
}

if in.Cmp(big.NewInt(0)) != 0 {
intTx := t.IO.In.AsInternal()
build += fmt.Sprintf("LT: %d, In: %s TON, From %s", t.LT, FromNanoTON(in).String(), intTx.SrcAddr)
build += fmt.Sprintf(", In: %s TON, From %s", FromNanoTON(in).String(), intTx.SrcAddr)
comment := intTx.Comment()
if comment != "" {
build += ", Comment: " + comment
}
} else if t.IO.In.MsgType == MsgTypeExternalIn {
exTx := t.IO.In.AsExternalIn()
build += ", ExternalIn, hash: " + hex.EncodeToString(exTx.Body.Hash())
}
}

Expand Down
11 changes: 11 additions & 0 deletions ton/jetton/jetton.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package jetton

import (
"context"
"errors"
"fmt"
"math/big"

Expand All @@ -19,6 +20,8 @@ type TonApi interface {
SubscribeOnTransactions(workerCtx context.Context, addr *address.Address, lastProcessedLT uint64, channel chan<- *tlb.Transaction)
}

var ErrInvalidTransfer = errors.New("transfer is not verified")

type MintPayloadMasterMsg struct {
Opcode uint32 `tlb:"## 32"`
QueryID uint64 `tlb:"## 64"`
Expand All @@ -34,6 +37,14 @@ type MintPayload struct {
MasterMsg MintPayloadMasterMsg `tlb:"^"`
}

type TransferNotification struct {
_ tlb.Magic `tlb:"#7362d09c"`
QueryID uint64 `tlb:"## 64"`
Amount tlb.Coins `tlb:"."`
Sender *address.Address `tlb:"addr"`
ForwardPayload *cell.Cell `tlb:"either . ^"`
}

type Data struct {
TotalSupply *big.Int
Mintable bool
Expand Down

0 comments on commit 98d6ede

Please sign in to comment.