Add pure and object func on transaction
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
package transaction
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"math"
|
||||
|
||||
"github.com/block-vision/sui-go-sdk/models"
|
||||
"github.com/block-vision/sui-go-sdk/models/sui_types"
|
||||
"github.com/block-vision/sui-go-sdk/mystenbcs"
|
||||
"github.com/block-vision/sui-go-sdk/utils"
|
||||
)
|
||||
|
||||
type Transaction struct {
|
||||
@@ -70,19 +74,15 @@ func (tx *Transaction) Gas() Argument {
|
||||
}
|
||||
|
||||
func (tx *Transaction) Add(command Command) Argument {
|
||||
tx.Data.Commands = append(tx.Data.Commands, command)
|
||||
index := uint16(len(tx.Data.Commands) - 1)
|
||||
index := tx.Data.AddCommand(command)
|
||||
return createTransactionResult(index, nil)
|
||||
}
|
||||
|
||||
func (tx *Transaction) SplitCoins(coin Argument, amount []Argument) Argument {
|
||||
cmd := splitCoins(SplitCoinsValue{
|
||||
return tx.Add(splitCoins(SplitCoinsValue{
|
||||
Coin: coin,
|
||||
Amount: amount,
|
||||
})
|
||||
tx.Data.Commands = append(tx.Data.Commands, cmd)
|
||||
index := uint16(len(tx.Data.Commands) - 1)
|
||||
return createTransactionResult(index, nil)
|
||||
}))
|
||||
}
|
||||
|
||||
func (tx *Transaction) MergeCoins(destination Argument, sources []Argument) Argument {
|
||||
@@ -143,18 +143,99 @@ func (tx *Transaction) makeMoveVec(typeValue *string, elements []Argument) Argum
|
||||
}))
|
||||
}
|
||||
|
||||
func (tx *Transaction) Object(obj string) Argument {
|
||||
// TODO
|
||||
return InputObject{
|
||||
Value: obj,
|
||||
func (tx *Transaction) Object(inputObject InputObject) (Argument, error) {
|
||||
var callArg CallArg
|
||||
|
||||
// Get inputObject's ID
|
||||
var id string
|
||||
if inputObject.Value == nil {
|
||||
id = inputObject.ObjectId
|
||||
if id == "" {
|
||||
return nil, errors.New("object id is empty")
|
||||
}
|
||||
|
||||
callArg = UnresolvedObject{
|
||||
ObjectId: utils.NormalizeSuiAddress(id),
|
||||
}
|
||||
} else {
|
||||
objArg := inputObject.Value.Value
|
||||
switch objArg.(type) {
|
||||
case ImmOrOwnedObject:
|
||||
id = objArg.(ImmOrOwnedObject).Value.ObjectId
|
||||
case SharedObject:
|
||||
id = objArg.(SharedObject).Value.ObjectId
|
||||
case Receiving:
|
||||
id = objArg.(Receiving).Value.ObjectId
|
||||
default:
|
||||
return nil, errors.New("object value is not supported")
|
||||
}
|
||||
|
||||
callArg = Object{
|
||||
Value: objArg,
|
||||
}
|
||||
}
|
||||
|
||||
// Check obj id if exists in tx
|
||||
isInserted := false
|
||||
for _, input := range tx.Data.Inputs {
|
||||
var inputId string
|
||||
|
||||
switch input.(type) {
|
||||
case Object:
|
||||
obj := input.(Object).Value
|
||||
switch obj.(type) {
|
||||
case ImmOrOwnedObject:
|
||||
inputId = obj.(ImmOrOwnedObject).Value.ObjectId
|
||||
case SharedObject:
|
||||
inputId = obj.(SharedObject).Value.ObjectId
|
||||
case Receiving:
|
||||
inputId = obj.(Receiving).Value.ObjectId
|
||||
default:
|
||||
return nil, errors.New("object value on tx is not supported")
|
||||
}
|
||||
case UnresolvedObject:
|
||||
inputId = input.(UnresolvedObject).ObjectId
|
||||
}
|
||||
|
||||
if inputId == id {
|
||||
isInserted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isInserted {
|
||||
return nil, errors.New("object id already exists in tx")
|
||||
}
|
||||
|
||||
input := tx.Data.AddInput(callArg)
|
||||
arg := Input{
|
||||
Input: input.(Input).Input,
|
||||
Type: input.(Input).Type,
|
||||
}
|
||||
|
||||
return arg, nil
|
||||
}
|
||||
|
||||
func (tx *Transaction) Pure(input string) Argument {
|
||||
// TODO
|
||||
return InputPure{
|
||||
Value: []byte{},
|
||||
func (tx *Transaction) Pure(inputPure InputPure) (Argument, error) {
|
||||
value := inputPure.Value
|
||||
bcsEncodedMsg := bytes.Buffer{}
|
||||
bcsEncoder := mystenbcs.NewEncoder(&bcsEncodedMsg)
|
||||
err := bcsEncoder.Encode(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bcsBase64 := mystenbcs.ToBase64(bcsEncodedMsg.Bytes())
|
||||
|
||||
input := tx.Data.AddInput(Pure{
|
||||
bcsBase64,
|
||||
})
|
||||
arg := Input{
|
||||
Input: input.(Input).Input,
|
||||
Type: input.(Input).Type,
|
||||
}
|
||||
|
||||
return arg, nil
|
||||
}
|
||||
|
||||
func createTransactionResult(index uint16, length *uint16) Argument {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package transaction
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/block-vision/sui-go-sdk/models"
|
||||
"github.com/block-vision/sui-go-sdk/models/sui_types"
|
||||
)
|
||||
@@ -14,6 +16,23 @@ type TransactionData struct {
|
||||
Commands []Command
|
||||
}
|
||||
|
||||
func (td *TransactionData) AddCommand(command Command) (index uint16) {
|
||||
index = uint16(len(td.Commands))
|
||||
td.Commands = append(td.Commands, command)
|
||||
|
||||
return index
|
||||
}
|
||||
|
||||
func (td *TransactionData) AddInput(input CallArg) Argument {
|
||||
index := len(td.Inputs)
|
||||
td.Inputs = append(td.Inputs, input)
|
||||
|
||||
return Input{
|
||||
Input: uint16(index),
|
||||
Type: strings.ToLower(input.callArgKind()),
|
||||
}
|
||||
}
|
||||
|
||||
// GasData https://github.com/MystenLabs/sui/blob/fb27c6c7166f5e4279d5fd1b2ebc5580ca0e81b2/crates/sui-types/src/transaction.rs#L1600
|
||||
type GasData struct {
|
||||
Payment []sui_types.SuiObjectRef
|
||||
@@ -36,12 +55,15 @@ type ProgrammableTransaction struct {
|
||||
// CallArg https://github.com/MystenLabs/sui/blob/fb27c6c7166f5e4279d5fd1b2ebc5580ca0e81b2/crates/sui-types/src/transaction.rs#L80
|
||||
// - Pure
|
||||
// - Object
|
||||
// - UnresolvedPure
|
||||
// - UnresolvedObject
|
||||
type CallArg interface {
|
||||
callArgKind() string
|
||||
}
|
||||
|
||||
type Pure struct {
|
||||
Value []byte
|
||||
// BCSBates's Base64
|
||||
Bytes string
|
||||
}
|
||||
|
||||
func (p Pure) callArgKind() string {
|
||||
@@ -56,6 +78,22 @@ func (o Object) callArgKind() string {
|
||||
return "Object"
|
||||
}
|
||||
|
||||
type UnresolvedPure struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (u UnresolvedPure) callArgKind() string {
|
||||
return "UnresolvedPure"
|
||||
}
|
||||
|
||||
type UnresolvedObject struct {
|
||||
ObjectId string
|
||||
}
|
||||
|
||||
func (u UnresolvedObject) callArgKind() string {
|
||||
return "UnresolvedObject"
|
||||
}
|
||||
|
||||
// ObjectArg
|
||||
// - ImmOrOwnedObject
|
||||
// - SharedObject
|
||||
@@ -199,6 +237,7 @@ type UpgradeValue struct {
|
||||
|
||||
// Argument https://github.com/MystenLabs/sui/blob/fb27c6c7166f5e4279d5fd1b2ebc5580ca0e81b2/crates/sui-types/src/transaction.rs#L745
|
||||
// - GasCoin
|
||||
// - Input
|
||||
// - InputPure
|
||||
// - InputObject
|
||||
// - Result
|
||||
@@ -215,8 +254,18 @@ func (g GasCoin) argumentKind() string {
|
||||
return "GasCoin"
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
// Index
|
||||
Input uint16
|
||||
Type string
|
||||
}
|
||||
|
||||
func (i Input) argumentKind() string {
|
||||
return "Input"
|
||||
}
|
||||
|
||||
type InputPure struct {
|
||||
Value []byte
|
||||
Value string
|
||||
}
|
||||
|
||||
func (i InputPure) argumentKind() string {
|
||||
@@ -224,7 +273,8 @@ func (i InputPure) argumentKind() string {
|
||||
}
|
||||
|
||||
type InputObject struct {
|
||||
Value string
|
||||
ObjectId string
|
||||
Value *Object
|
||||
}
|
||||
|
||||
func (i InputObject) argumentKind() string {
|
||||
|
||||
@@ -6,11 +6,22 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/mr-tron/base58"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
)
|
||||
|
||||
func NormalizeSuiAddress(input string) string {
|
||||
addr := strings.ToLower(input)
|
||||
if strings.HasPrefix(addr, "0x") {
|
||||
addr = addr[2:]
|
||||
}
|
||||
|
||||
addr = strings.Repeat("0", 64-len(addr)) + addr
|
||||
return "0x" + addr
|
||||
}
|
||||
|
||||
func PrettyPrint(v interface{}) {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
|
||||
48
utils/utils_test.go
Normal file
48
utils/utils_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNormalizeSuiAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
description string
|
||||
}{
|
||||
{
|
||||
input: "abc",
|
||||
expected: "0x0000000000000000000000000000000000000000000000000000000000000abc",
|
||||
description: "lowercase without 0x",
|
||||
},
|
||||
{
|
||||
input: "0xabc",
|
||||
expected: "0x0000000000000000000000000000000000000000000000000000000000000abc",
|
||||
description: "with 0x, no forceAdd0x",
|
||||
},
|
||||
{
|
||||
input: "0xABC",
|
||||
expected: "0x0000000000000000000000000000000000000000000000000000000000000abc",
|
||||
description: "uppercase input, normalize to lowercase",
|
||||
},
|
||||
{
|
||||
input: "abc",
|
||||
expected: "0x0000000000000000000000000000000000000000000000000000000000000abc",
|
||||
description: "forceAdd0x with plain input",
|
||||
},
|
||||
{
|
||||
input: "0xabc",
|
||||
expected: "0x0000000000000000000000000000000000000000000000000000000000000abc",
|
||||
description: "forceAdd0x true keeps 0xabc and still pads correctly",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
result := NormalizeSuiAddress(test.input)
|
||||
if result != test.expected {
|
||||
t.Errorf("expected %s, got %s", test.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user