diff --git a/address/addr.go b/address/addr.go index bd114f66..5822628a 100644 --- a/address/addr.go +++ b/address/addr.go @@ -6,6 +6,8 @@ import ( "encoding/hex" "errors" "fmt" + "strconv" + "strings" "github.com/sigurn/crc16" ) @@ -206,6 +208,14 @@ func MustParseAddr(addr string) *Address { return a } +func MustParseRawAddr(addr string) *Address { + a, err := ParseRawAddr(addr) + if err != nil { + panic(err) + } + return a +} + func (a *Address) FlagsToByte() (flags byte) { // TODO check this magic... flags = 0b00010001 @@ -244,6 +254,28 @@ func ParseAddr(addr string) (*Address, error) { return a, nil } +func ParseRawAddr(addr string) (*Address, error) { + addrParts := strings.SplitN(addr, ":", 2) + if len(addrParts) != 2 { + return nil, fmt.Errorf("invalid address format") + } + + data, err := hex.DecodeString(addrParts[1]) + if err != nil { + return nil, err + } + + if len(data) != 32 { + return nil, errors.New("incorrect address data length") + } + + wc, err := strconv.ParseInt(addrParts[0], 10, 8) + if err != nil { + return nil, err + } + return NewAddress(0, byte(wc), data), nil +} + func (a *Address) Checksum() uint16 { return crc16.Checksum(a.prepareChecksumData(), crc16.MakeTable(crc16.CRC16_XMODEM)) } diff --git a/address/addr_test.go b/address/addr_test.go index acbcd0d0..e9a76c57 100644 --- a/address/addr_test.go +++ b/address/addr_test.go @@ -391,6 +391,27 @@ func TestMustParseAddr(t *testing.T) { } } +func TestMustParseRawAddr(t *testing.T) { + tests := []struct { + name string + args string + want *Address + }{ + {"1", "0:1212121212121212121212121212121212121212121212121212121212121212", &Address{addrType: StdAddress, bitsLen: 256, flags: flags{bounceable: true, testnet: false}, workchain: 0, data: []byte{0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}}}, + {"2", "-1:1212121212121212121212121212121212121212121212121212121212121212", &Address{addrType: StdAddress, bitsLen: 256, flags: flags{bounceable: true, testnet: false}, workchain: -1, data: []byte{0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}}}, + {"3", "127:1212121212121212121212121212121212121212121212121212121212121212", &Address{addrType: StdAddress, bitsLen: 256, flags: flags{bounceable: true, testnet: false}, workchain: 127, data: []byte{0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}}}, + {"4", "-127:1212121212121212121212121212121212121212121212121212121212121212", &Address{addrType: StdAddress, bitsLen: 256, flags: flags{bounceable: true, testnet: false}, workchain: -127, data: []byte{0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := MustParseRawAddr(tt.args); !reflect.DeepEqual(got, tt.want) { + fmt.Printf("test: %#v", got.flags) + t.Errorf("MustParseAddr() = %v, want %v", got, tt.want) + } + }) + } +} + func TestNewAddressFromBytes(t *testing.T) { type args struct { flags byte diff --git a/example/jetton-transfer/main.go b/example/jetton-transfer/main.go index f4b76c7e..d07c3f08 100644 --- a/example/jetton-transfer/main.go +++ b/example/jetton-transfer/main.go @@ -59,7 +59,7 @@ func main() { // address of receiver's wallet (not token wallet, just usual) to := address.MustParseAddr("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N") - transferPayload, err := tokenWallet.BuildTransferPayload(to, amountTokens, tlb.ZeroCoins, comment) + transferPayload, err := tokenWallet.BuildTransferPayloadV2(to, to, amountTokens, tlb.ZeroCoins, comment, nil) if err != nil { log.Fatal(err) } diff --git a/ton/jetton/wallet.go b/ton/jetton/wallet.go index c49ad396..6ee7bfd1 100644 --- a/ton/jetton/wallet.go +++ b/ton/jetton/wallet.go @@ -66,7 +66,12 @@ func (c *WalletClient) GetBalanceAtBlock(ctx context.Context, b *ton.BlockIDExt) return balance, nil } +// Deprecated: use BuildTransferPayloadV2 func (c *WalletClient) BuildTransferPayload(to *address.Address, amountCoins, amountForwardTON tlb.Coins, payloadForward *cell.Cell) (*cell.Cell, error) { + return c.BuildTransferPayloadV2(to, to, amountCoins, amountForwardTON, payloadForward, nil) +} + +func (c *WalletClient) BuildTransferPayloadV2(to, responseTo *address.Address, amountCoins, amountForwardTON tlb.Coins, payloadForward, customPayload *cell.Cell) (*cell.Cell, error) { if payloadForward == nil { payloadForward = cell.BeginCell().EndCell() } @@ -81,8 +86,8 @@ func (c *WalletClient) BuildTransferPayload(to *address.Address, amountCoins, am QueryID: rnd, Amount: amountCoins, Destination: to, - ResponseDestination: to, - CustomPayload: nil, + ResponseDestination: responseTo, + CustomPayload: customPayload, ForwardTONAmount: amountForwardTON, ForwardPayload: payloadForward, }) diff --git a/ton/nft/integration_test.go b/ton/nft/integration_test.go index c87691c9..fb79ab91 100644 --- a/ton/nft/integration_test.go +++ b/ton/nft/integration_test.go @@ -86,11 +86,17 @@ func Test_NftMintTransfer(t *testing.T) { fmt.Println("Minting NFT...") mint := wallet.SimpleMessage(collectionAddr, tlb.MustFromTON("0.025"), mintData) - err = w.Send(ctx, mint, true) + _, block, err = w.SendWaitTransaction(context.Background(), mint) if err != nil { t.Fatal("Send err:", err.Error()) } + // wait next block to be sure everything updated + block, err = api.WaitForBlock(block.SeqNo + 5).GetMasterchainInfo(ctx) + if err != nil { + t.Fatal("Wait master err:", err.Error()) + } + fmt.Println("Minted NFT:", nftAddr.String(), 0) newAddr := address.MustParseAddr("EQB9ElEc88x6kOZytvUp0_18U-W1V-lBdvPcZ-BXdBWVrmeA") // address wallet with other seed = ("together ... lounge") @@ -109,7 +115,7 @@ func Test_NftMintTransfer(t *testing.T) { } // wait next block to be sure everything updated - block, err = api.WaitForBlock(block.SeqNo + 7).GetMasterchainInfo(ctx) + block, err = api.WaitForBlock(block.SeqNo + 5).GetMasterchainInfo(ctx) if err != nil { t.Fatal("Wait master err:", err.Error()) } diff --git a/tvm/cell/dict.go b/tvm/cell/dict.go index caa49729..19bb80d3 100644 --- a/tvm/cell/dict.go +++ b/tvm/cell/dict.go @@ -139,7 +139,7 @@ func (d *Dictionary) Set(key, value *Cell) error { if matches { if pfx.BitsLeft() == 0 { // label is same with our new key, we just need to change value - return d.storeLeaf(kPart.ToSlice(), val, keyOffset-bitsMatches) + return d.storeLeaf(kPart.ToSlice(), val, keyOffset) } // full label is matches part of our key, we need to go deeper diff --git a/tvm/cell/dict_test.go b/tvm/cell/dict_test.go index 408ede50..fe4a0597 100644 --- a/tvm/cell/dict_test.go +++ b/tvm/cell/dict_test.go @@ -173,9 +173,9 @@ func TestLoadCell_DictShuffle(t *testing.T) { for i := 0; i < 120000; i++ { rnd := make([]byte, 8) _, _ = rand.Read(rnd) - _ = mm.SetIntKey(new(big.Int).SetBytes(rnd), empty) + _ = mm.SetIntKey(new(big.Int).Mod(new(big.Int).SetBytes(rnd), big.NewInt(65000)), empty) } - hh, _ := mm.MustToCell().BeginParse().ToDict(64) + hh, _ := mm.AsCell().BeginParse().ToDict(64) for _, kv := range mm.All() { if hh.Get(kv.Key) == nil { @@ -265,3 +265,32 @@ func TestDictionary_Make(t *testing.T) { } println(sl.MustToCell().Dump()) } + +func Test_ReplaceDict(t *testing.T) { + k := big.NewInt(1) + k2 := big.NewInt(2) + v := BeginCell().EndCell() + + dict := NewDict(64) + + if err := dict.SetIntKey(k, v); err != nil { + panic(err) + } + if err := dict.SetIntKey(k2, v); err != nil { + panic(err) + } + + if err := dict.SetIntKey(k, v); err != nil { + panic(err) + } + if err := dict.SetIntKey(k2, v); err != nil { + panic(err) + } + + if err := dict.SetIntKey(k, v); err != nil { + panic(err) + } + if err := dict.SetIntKey(k2, v); err != nil { + panic(err) + } +}