Skip to content

Commit

Permalink
Merge pull request #218 from xssnick/dev-v19
Browse files Browse the repository at this point in the history
v1.9.9
  • Loading branch information
xssnick authored Jul 25, 2024
2 parents c0b96b2 + 2ec0b5d commit 1a9b826
Show file tree
Hide file tree
Showing 15 changed files with 379 additions and 105 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 event 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
12 changes: 6 additions & 6 deletions example/deploy-nft-collection/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ func main() {

func getWallet(api ton.APIClientWrapped) *wallet.Wallet {
words := strings.Split("birth pattern then forest walnut then phrase walnut fan pumpkin pattern then cluster blossom verify then forest velvet pond fiction pattern collect then then", " ")
w, err := wallet.FromSeed(api, words, wallet.V3)
w, err := wallet.FromSeed(api, words, wallet.V4R2)
if err != nil {
panic(err)
}
return w
}

func getNFTCollectionCode() *cell.Cell {
var hexBOC = "b5ee9c72410213010001fe000114ff00f4a413f4bcf2c80b0102016204020201200e030025bc82df6a2687d20699fea6a6a182de86a182c40202cd0a050201200706003d45af0047021f005778018c8cb0558cf165004fa0213cb6b12ccccc971fb0080201200908001b3e401d3232c084b281f2fff27420002d007232cffe0a33c5b25c083232c044fd003d0032c0326003ebd10638048adf000e8698180b8d848adf07d201800e98fe99ff6a2687d20699fea6a6a184108349e9ca829405d47141baf8280e8410854658056b84008646582a802e78b127d010a65b509e58fe59f80e78b64c0207d80701b28b9e382f970c892e000f18112e001718119026001f1812f82c207f97840d0c0b002801fa40304144c85005cf1613cb3fccccccc9ed5400a6357003d4308e378040f4966fa5208e2906a4208100fabe93f2c18fde81019321a05325bbf2f402fa00d43022544b30f00623ba9302a402de04926c21e2b3e6303250444313c85005cf1613cb3fccccccc9ed5400603502d33f5313bbf2e1925313ba01fa00d43028103459f0068e1201a44343c85005cf1613cb3fccccccc9ed54925f05e2020120120f0201201110002db4f47da89a1f481a67fa9a9a86028be09e008e003e00b0002fb5dafda89a1f481a67fa9a9a860d883a1a61fa61ff4806100043b8b5d31ed44d0fa40d33fd4d4d43010245f04d0d431d430d071c8cb0701cf16ccc98f34ea10e"
var hexBOC = "b5ee9c724102140100021f000114ff00f4a413f4bcf2c80b0102016202030202cd04050201200e0f04e7d10638048adf000e8698180b8d848adf07d201800e98fe99ff6a2687d20699fea6a6a184108349e9ca829405d47141baf8280e8410854658056b84008646582a802e78b127d010a65b509e58fe59f80e78b64c0207d80701b28b9e382f970c892e000f18112e001718112e001f181181981e0024060708090201200a0b00603502d33f5313bbf2e1925313ba01fa00d43028103459f0068e1201a44343c85005cf1613cb3fccccccc9ed54925f05e200a6357003d4308e378040f4966fa5208e2906a4208100fabe93f2c18fde81019321a05325bbf2f402fa00d43022544b30f00623ba9302a402de04926c21e2b3e6303250444313c85005cf1613cb3fccccccc9ed54002c323401fa40304144c85005cf1613cb3fccccccc9ed54003c8e15d4d43010344130c85005cf1613cb3fccccccc9ed54e05f04840ff2f00201200c0d003d45af0047021f005778018c8cb0558cf165004fa0213cb6b12ccccc971fb008002d007232cffe0a33c5b25c083232c044fd003d0032c03260001b3e401d3232c084b281f2fff2742002012010110025bc82df6a2687d20699fea6a6a182de86a182c40043b8b5d31ed44d0fa40d33fd4d4d43010245f04d0d431d430d071c8cb0701cf16ccc980201201213002fb5dafda89a1f481a67fa9a9a860d883a1a61fa61ff480610002db4f47da89a1f481a67fa9a9a86028be09e008e003e00b01a500c6e"
codeCellBytes, _ := hex.DecodeString(hexBOC)

codeCell, err := cell.FromBOC(codeCellBytes)
Expand All @@ -65,7 +65,7 @@ func getNFTCollectionCode() *cell.Cell {
}

func getNFTItemCode() *cell.Cell {
var hexBOC = "b5ee9c7241020d010001d0000114ff00f4a413f4bcf2c80b0102016203020009a11f9fe0050202ce050402012008060201200907001d00f232cfd633c58073c5b3327b552000113e910c1c2ebcb85360003b3b513434cffe900835d27080269fc07e90350c04090408f80c1c165b5b6002d70c8871c02497c0f83434c0c05c6c2497c0f83e903e900c7e800c5c75c87e800c7e800c3c00812ce3850c1b088d148cb1c17cb865407e90350c0408fc00f801b4c7f4cfe08417f30f45148c2ea3a1cc840dd78c9004f80c0d0d0d4d60840bf2c9a884aeb8c097c12103fcbc200b0a00727082108b77173505c8cbff5004cf1610248040708010c8cb055007cf165005fa0215cb6a12cb1fcb3f226eb39458cf17019132e201c901fb0001f65135c705f2e191fa4021f001fa40d20031fa00820afaf0801ba121945315a0a1de22d70b01c300209206a19136e220c2fff2e192218e3e821005138d91c85009cf16500bcf16712449145446a0708010c8cb055007cf165005fa0215cb6a12cb1fcb3f226eb39458cf17019132e201c901fb00104794102a375be20c0082028e3526f0018210d53276db103744006d71708010c8cb055007cf165005fa0215cb6a12cb1fcb3f226eb39458cf17019132e201c901fb0093303234e25502f003cc82807e"
var hexBOC = "b5ee9c7241020d010001d0000114ff00f4a413f4bcf2c80b0102016202030202ce04050009a11f9fe00502012006070201200b0c02d70c8871c02497c0f83434c0c05c6c2497c0f83e903e900c7e800c5c75c87e800c7e800c3c00812ce3850c1b088d148cb1c17cb865407e90350c0408fc00f801b4c7f4cfe08417f30f45148c2ea3a1cc840dd78c9004f80c0d0d0d4d60840bf2c9a884aeb8c097c12103fcbc20080900113e910c1c2ebcb8536001f65135c705f2e191fa4021f001fa40d20031fa00820afaf0801ba121945315a0a1de22d70b01c300209206a19136e220c2fff2e192218e3e821005138d91c85009cf16500bcf16712449145446a0708010c8cb055007cf165005fa0215cb6a12cb1fcb3f226eb39458cf17019132e201c901fb00104794102a375be20a00727082108b77173505c8cbff5004cf1610248040708010c8cb055007cf165005fa0215cb6a12cb1fcb3f226eb39458cf17019132e201c901fb000082028e3526f0018210d53276db103744006d71708010c8cb055007cf165005fa0215cb6a12cb1fcb3f226eb39458cf17019132e201c901fb0093303234e25502f003003b3b513434cffe900835d27080269fc07e90350c04090408f80c1c165b5b60001d00f232cfd633c58073c5b3327b5520bf75041b"
codeCellBytes, _ := hex.DecodeString(hexBOC)

codeCell, err := cell.FromBOC(codeCellBytes)
Expand All @@ -86,9 +86,9 @@ func getContractData(collectionOwnerAddr, royaltyAddr *address.Address) *cell.Ce
// = Storage;

royalty := cell.BeginCell().
MustStoreUInt(50, 16). // 5% royalty
MustStoreUInt(1000, 16).
MustStoreAddr(royaltyAddr).
MustStoreUInt(5, 16). // 5% royalty
MustStoreUInt(100, 16). // denominator
MustStoreAddr(royaltyAddr). // fee addr destination
EndCell()

// collection data
Expand Down
2 changes: 1 addition & 1 deletion example/nft-mint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func main() {

func getWallet(api *ton.APIClient) *wallet.Wallet {
words := strings.Split("birth pattern then forest walnut then phrase walnut fan pumpkin pattern then cluster blossom verify then forest velvet pond fiction pattern collect then then", " ")
w, err := wallet.FromSeed(api, words, wallet.V3)
w, err := wallet.FromSeed(api, words, wallet.V4R2)
if err != nil {
panic(err)
}
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
12 changes: 6 additions & 6 deletions ton/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ type ShardInfo struct {
ID *BlockIDExt `tl:"struct"`
ShardBlock *BlockIDExt `tl:"struct"`
ShardProof []*cell.Cell `tl:"cell optional 2"`
ShardDescription *cell.Cell `tl:"bytes"`
ShardDescription *cell.Cell `tl:"cell optional"`
}

type BlockTransactions struct {
Expand All @@ -194,11 +194,11 @@ type BlockTransactions struct {
}

type BlockTransactionsExt struct {
ID *BlockIDExt `tl:"struct"`
ReqCount int32 `tl:"int"`
Incomplete bool `tl:"bool"`
Transactions *cell.Cell `tl:"cell optional"`
Proof []byte `tl:"bytes"`
ID *BlockIDExt `tl:"struct"`
ReqCount int32 `tl:"int"`
Incomplete bool `tl:"bool"`
Transactions []*cell.Cell `tl:"cell optional"`
Proof []byte `tl:"bytes"`
}

type BlockData struct {
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
6 changes: 6 additions & 0 deletions ton/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ func (c *APIClient) findLastTransactionByHash(ctx context.Context, addr *address
}

if isOut {
if transaction.IO.Out == nil {
continue
}

list, err := transaction.IO.Out.ToSlice()
if err != nil {
return nil, fmt.Errorf("cannot list out messages: %w", err)
Expand All @@ -334,6 +338,8 @@ func (c *APIClient) findLastTransactionByHash(ctx context.Context, addr *address
return transaction, nil
}
}

continue
} else {
if transaction.IO.In == nil {
continue
Expand Down
44 changes: 33 additions & 11 deletions ton/wallet/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ func GetStateInit(pubKey ed25519.PublicKey, version VersionConfig, subWallet uin
switch ver {
case HighloadV3:
return nil, fmt.Errorf("use ConfigHighloadV3 for highload v3 spec")
case V5R1:
return nil, fmt.Errorf("use ConfigV5R1 for v5 spec")
case V5R1Beta:
return nil, fmt.Errorf("use ConfigV5R1Beta for V5 spec")
case V5R1Final:
return nil, fmt.Errorf("use ConfigV5R1Final for V5 spec")
}
case ConfigHighloadV3:
ver = HighloadV3
case ConfigV5R1:
ver = V5R1
case ConfigV5R1Beta:
ver = V5R1Beta
case ConfigV5R1Final:
ver = V5R1Final
}

code, ok := walletCode[ver]
Expand All @@ -84,18 +88,36 @@ func GetStateInit(pubKey ed25519.PublicKey, version VersionConfig, subWallet uin
MustStoreSlice(pubKey, 256).
MustStoreDict(nil). // empty dict of plugins
EndCell()
case V5R1:
config := version.(ConfigV5R1)
case V5R1Beta:
config := version.(ConfigV5R1Beta)

data = cell.BeginCell().
MustStoreUInt(0, 33). // seqno
MustStoreInt(int64(config.NetworkGlobalID), 32).
MustStoreInt(int64(config.Workchain), 8).
MustStoreUInt(0, 8). // version of v5
MustStoreUInt(uint64(subWallet), 32).
MustStoreUInt(0, 33). // seqno
MustStoreInt(int64(config.NetworkGlobalID), 32). // network id
MustStoreInt(int64(config.Workchain), 8). // workchain
MustStoreUInt(0, 8). // version of v5
MustStoreUInt(uint64(subWallet), 32). // default 0
MustStoreSlice(pubKey, 256).
MustStoreDict(nil). // empty dict of plugins
EndCell()
case V5R1Final:
config := version.(ConfigV5R1Final)

// Create WalletId instance
walletId := V5R1ID{
NetworkGlobalID: config.NetworkGlobalID, // -3 Testnet, -239 Mainnet
WorkChain: config.Workchain,
SubwalletNumber: uint16(subWallet),
WalletVersion: 0, // Wallet Version
}

data = cell.BeginCell().
MustStoreBoolBit(true). // storeUint(1, 1) - boolean flag for context type
MustStoreUInt(0, 32). // Sequence number, hardcoded as 0
MustStoreUInt(uint64(walletId.Serialized()), 32). // Serializing WalletId into 32-bit integer
MustStoreSlice(pubKey, 256). // Storing the public key
MustStoreDict(nil). // Storing an empty plugins dictionary
EndCell()
case HighloadV2R2, HighloadV2Verified:
data = cell.BeginCell().
MustStoreUInt(uint64(subWallet), 32).
Expand Down
19 changes: 16 additions & 3 deletions ton/wallet/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func Test_HighloadHeavyTransfer(t *testing.T) {
func Test_V5HeavyTransfer(t *testing.T) {
seed := strings.Split(_seed, " ")

w, err := FromSeed(api, seed, ConfigV5R1{
w, err := FromSeed(api, seed, ConfigV5R1Final{
NetworkGlobalID: MainnetGlobalID,
})
if err != nil {
Expand Down Expand Up @@ -114,7 +114,9 @@ func Test_V5HeavyTransfer(t *testing.T) {
func Test_WalletTransfer(t *testing.T) {
seed := strings.Split(_seed, " ")

for _, v := range []VersionConfig{ConfigV5R1{
for _, v := range []VersionConfig{ConfigV5R1Final{
NetworkGlobalID: TestnetGlobalID,
}, ConfigV5R1Beta{
NetworkGlobalID: TestnetGlobalID,
}, V3R2, V4R2, HighloadV2R2, V3R1, V4R1, HighloadV2Verified, ConfigHighloadV3{
MessageTTL: 120,
Expand Down Expand Up @@ -164,11 +166,22 @@ func Test_WalletTransfer(t *testing.T) {
comment := randString(150)
addr := address.MustParseAddr("EQA8aJTl0jfFnUZBJjTeUxu9OcbsoPBp9UcHE9upyY_X35kE")
if balance.Nano().Uint64() >= 3000000 {
err = w.Transfer(ctx, addr, tlb.MustFromTON("0.003"), comment, true)
tr, err := w.BuildTransfer(addr, tlb.MustFromTON("0.003"), false, comment)
if err != nil {
t.Fatal("Build transfer err:", err.Error())
return
}

tx, _, err := w.SendManyWaitTransaction(ctx, []*Message{tr})
if err != nil {
t.Fatal("Transfer err:", err.Error())
return
}

if tx.OutMsgCount == 0 {
t.Fatal("Out msg is 0:", ver)
return
}
} else {
t.Fatal("not enough balance")
return
Expand Down
Loading

0 comments on commit 1a9b826

Please sign in to comment.