-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from xssnick/ext-msg
External message support
- Loading branch information
Showing
9 changed files
with
278 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"log" | ||
|
||
"github.com/xssnick/tonutils-go/address" | ||
"github.com/xssnick/tonutils-go/liteclient" | ||
"github.com/xssnick/tonutils-go/ton" | ||
"github.com/xssnick/tonutils-go/tvm/cell" | ||
) | ||
|
||
/* | ||
This example is for such contract. | ||
It is recommended to deploy your own before run this script | ||
because this address can have not enough TON due to many executions of this example. | ||
Or you can at least add some coins to contract address | ||
() recv_external(slice in_msg) impure { | ||
int seqno = in_msg~load_uint(64); | ||
int n = in_msg.preload_uint(16); | ||
var data = get_data().begin_parse(); | ||
int stored_seq = data~load_uint(64); | ||
throw_if(409, seqno != stored_seq); | ||
accept_message(); | ||
int total = data.preload_uint(64); | ||
set_data(begin_cell().store_uint(stored_seq + 1, 64).store_uint(total + n, 64).end_cell()); | ||
} | ||
(int, int) get_total() method_id { | ||
var data = get_data().begin_parse(); | ||
int stored_seq = data~load_uint(64); | ||
return (stored_seq, data.preload_uint(64)); | ||
} | ||
*/ | ||
|
||
func main() { | ||
client := liteclient.NewClient() | ||
|
||
// connect to testnet lite server | ||
err := client.Connect(context.Background(), "65.21.74.140:46427", "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=") | ||
if err != nil { | ||
log.Fatalln("connection err: ", err.Error()) | ||
return | ||
} | ||
|
||
// initialize ton api lite connection wrapper | ||
api := ton.NewAPIClient(client) | ||
|
||
// we need fresh block info to run get methods | ||
block, err := api.GetBlockInfo(context.Background()) | ||
if err != nil { | ||
log.Fatalln("get block err:", err.Error()) | ||
return | ||
} | ||
|
||
// call method to get seqno of contract | ||
res, err := api.RunGetMethod(context.Background(), block, address.MustParseAddr("kQBkh8dcas3_OB0uyFEDdVBBSpAWNEgdQ66OYF76N4cDXAFQ"), "get_total") | ||
if err != nil { | ||
log.Fatalln("run get method err:", err.Error()) | ||
return | ||
} | ||
|
||
seqno := res[0].(uint64) | ||
total := res[1].(uint64) | ||
|
||
log.Printf("Current seqno = %d and total = %d", seqno, total) | ||
|
||
data := cell.BeginCell(). | ||
MustStoreUInt(seqno, 64). | ||
MustStoreUInt(1, 16). // add 1 to total | ||
EndCell() | ||
|
||
err = api.SendExternalMessage(context.Background(), address.MustParseAddr("kQBkh8dcas3_OB0uyFEDdVBBSpAWNEgdQ66OYF76N4cDXAFQ"), data) | ||
if err != nil { | ||
// FYI: it can fail if not enough balance on contract | ||
log.Printf("send err: %s", err.Error()) | ||
return | ||
} | ||
|
||
log.Println("External message successfully processed and should be added to blockchain soon!") | ||
log.Println("Rerun this script in a couple seconds and you should see total and seqno changed.") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package ton | ||
|
||
import ( | ||
"context" | ||
"encoding/binary" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/xssnick/tonutils-go/address" | ||
"github.com/xssnick/tonutils-go/tvm/cell" | ||
) | ||
|
||
var ErrMessageNotAccepted = errors.New("message was not accepted by the contract") | ||
|
||
func (c *APIClient) SendExternalMessage(ctx context.Context, addr *address.Address, msg *cell.Cell) error { | ||
return c.sendExternalMessage(ctx, addr, msg) | ||
} | ||
|
||
func (c *APIClient) sendExternalMessage(ctx context.Context, addr *address.Address, msg any) error { | ||
builder := cell.BeginCell().MustStoreUInt(0b10, 2). | ||
MustStoreUInt(0b00, 2). // src addr_none | ||
MustStoreAddr(addr). // dst addr | ||
MustStoreCoins(0) // import fee 0 | ||
|
||
builder.MustStoreUInt(0, 1) // no state init | ||
|
||
switch d := msg.(type) { | ||
case []byte: // slice data | ||
builder.MustStoreUInt(0, 1).MustStoreSlice(d, len(d)*8) | ||
case *cell.Cell: // cell data | ||
builder.MustStoreUInt(1, 1).MustStoreRef(d) | ||
default: | ||
return errors.New("unknown arg type") | ||
} | ||
|
||
req := builder.EndCell().ToBOCWithFlags(false) | ||
|
||
resp, err := c.client.Do(ctx, _SendMessage, storableBytes(req)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
switch resp.TypeID { | ||
case _SendMessageResult: | ||
// TODO: mode | ||
status := binary.LittleEndian.Uint32(resp.Data) | ||
|
||
if status != 1 { | ||
return fmt.Errorf("status: %d", status) | ||
} | ||
|
||
return nil | ||
case _LSError: | ||
code := binary.LittleEndian.Uint32(resp.Data) | ||
if code == 0 { | ||
return ErrMessageNotAccepted | ||
} | ||
|
||
return fmt.Errorf("lite server error, code %d: %s", code, string(resp.Data[5:])) | ||
} | ||
|
||
return errors.New("unknown response type") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.