diff --git a/go.mod b/go.mod index be706c3c..559b990a 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/golang/mock v1.3.1 github.com/google/go-cmp v0.3.1 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.4.0 ) diff --git a/go.sum b/go.sum index 28273fe2..e83abe8a 100644 --- a/go.sum +++ b/go.sum @@ -209,6 +209,7 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= diff --git a/mercury/api.go b/mercury/api.go new file mode 100644 index 00000000..79809ca2 --- /dev/null +++ b/mercury/api.go @@ -0,0 +1,66 @@ +package mercury + +import ( + "github.com/ethereum/go-ethereum/rpc" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/action" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/resp" + "github.com/pkg/errors" +) + +type MercuryApi interface { + GetBalance(udthash interface{}, ident string) (*resp.Balance, error) + BuildTransferTransaction(payload *model.TransferPayload) (*resp.TransferCompletionResponse, error) + BuildWalletCreationTransaction(payload *model.CreateWalletPayload) (*resp.TransferCompletionResponse, error) +} + +type DefaultMercuryApi struct { + c *rpc.Client +} + +func (cli *DefaultMercuryApi) GetBalance(udthash interface{}, ident string) (*resp.Balance, error) { + var balance resp.Balance + err := cli.c.Call(&balance, "get_balance", udthash, ident) + if err != nil { + return &balance, err + } + + return &balance, err +} + +func (cli *DefaultMercuryApi) BuildTransferTransaction(payload *model.TransferPayload) (*resp.TransferCompletionResponse, error) { + var resp resp.TransferCompletionResponse + if payload.UdtHash == "" { + for _, item := range payload.Items { + if item.To.Action == action.Lend_by_from || item.To.Action == action.Pay_by_to { + return &resp, errors.New("The transaction does not support ckb") + } + } + } + + err := cli.c.Call(&resp, "build_transfer_transaction", payload) + if err != nil { + return &resp, err + } + + return &resp, err +} + +func (cli *DefaultMercuryApi) BuildWalletCreationTransaction(payload *model.CreateWalletPayload) (*resp.TransferCompletionResponse, error) { + var resp resp.TransferCompletionResponse + err := cli.c.Call(&resp, "build_wallet_creation_transaction", payload) + if err != nil { + return &resp, err + } + + return &resp, err +} + +func NewMercuryApi(address string) (MercuryApi, error) { + dial, err := rpc.Dial(address) + if err != nil { + return &DefaultMercuryApi{}, err + } + + return &DefaultMercuryApi{dial}, err +} diff --git a/mercury/model/action/action.go b/mercury/model/action/action.go new file mode 100644 index 00000000..a2ccef67 --- /dev/null +++ b/mercury/model/action/action.go @@ -0,0 +1,7 @@ +package action + +const ( + Pay_by_from = "pay_by_from" + Lend_by_from = "lend_by_from" + Pay_by_to = "pay_by_to" +) diff --git a/mercury/model/create_wallet_payload.go b/mercury/model/create_wallet_payload.go new file mode 100644 index 00000000..f81ed03c --- /dev/null +++ b/mercury/model/create_wallet_payload.go @@ -0,0 +1,38 @@ +package model + +type CreateWalletPayload struct { + Ident string `json:"ident"` + Info []*WalletInfo `json:"info"` + Fee uint `json:"fee"` +} +type WalletInfo struct { + UdtHash string `json:"udt_hash"` +} + +type CreateWalletPayloadBuilder struct { + Ident string `json:"ident"` + Info []*WalletInfo `json:"info"` + Fee uint `json:"fee"` +} + +func (walletPayload *CreateWalletPayload) AddIdent(ident string) { + walletPayload.Ident = ident +} + +func (walletPayload *CreateWalletPayload) AddFee(fee uint) { + walletPayload.Fee = fee +} + +func (walletPayload *CreateWalletPayload) AddInfo(udtHash string) { + walletPayload.Info = append(walletPayload.Info, &WalletInfo{ + UdtHash: udtHash, + }) +} + +func (walletPayload *CreateWalletPayload) Build() *CreateWalletPayload { + return &CreateWalletPayload{ + Ident: walletPayload.Ident, + Info: walletPayload.Info, + Fee: walletPayload.Fee, + } +} diff --git a/mercury/model/resp/balance.go b/mercury/model/resp/balance.go new file mode 100644 index 00000000..b80a6869 --- /dev/null +++ b/mercury/model/resp/balance.go @@ -0,0 +1,7 @@ +package resp + +type Balance struct { + Unconstrained string `json:"owned"` + Fleeting string `json:"claimable"` + locked string `json:"locked"` +} diff --git a/mercury/model/resp/transcation.go b/mercury/model/resp/transcation.go new file mode 100644 index 00000000..ec31c599 --- /dev/null +++ b/mercury/model/resp/transcation.go @@ -0,0 +1,130 @@ +package resp + +import ( + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/nervosnetwork/ckb-sdk-go/transaction" + "github.com/nervosnetwork/ckb-sdk-go/types" +) + +type TransferCompletionResponse struct { + TxView transactionResp `json:"tx_view"` + SigsEntry []*SignatureEntry `json:"sigs_entry"` +} + +type SignatureEntry struct { + Type string `json:"type"` + Index int `json:"index"` + PubKey string `json:"pub_key"` + GroupLen int `json:"group_len"` +} + +type ScriptGroup struct { + Group []int + WitnessArgs *types.WitnessArgs + PubKey string +} + +func (self *TransferCompletionResponse) GetTransaction() *types.Transaction { + return toTransaction(self.TxView) +} + +func (self *TransferCompletionResponse) GetScriptGroup() []*ScriptGroup { + groupScripts := make([]*ScriptGroup, len(self.SigsEntry)) + + self.TxView.Witnesses = make([]hexutil.Bytes, len(self.TxView.Inputs)) + for i, _ := range self.TxView.Witnesses { + self.TxView.Witnesses[i] = []byte{} + } + + for index, entry := range self.SigsEntry { + group := make([]int, entry.GroupLen) + groupIndex := 0 + for i := entry.Index; i < entry.Index+entry.GroupLen; i++ { + group[groupIndex] = i + groupIndex += 1 + } + + groupScripts[index] = &ScriptGroup{ + Group: group, + WitnessArgs: transaction.EmptyWitnessArg, + PubKey: entry.PubKey, + } + + self.TxView.Witnesses[entry.Index] = transaction.EmptyWitnessArgPlaceholder + } + return groupScripts +} + +func toTransaction(tx transactionResp) *types.Transaction { + return &types.Transaction{ + Version: uint(tx.Version), + Hash: tx.Hash, + CellDeps: toCellDeps(tx.CellDeps), + HeaderDeps: tx.HeaderDeps, + Inputs: toInputs(tx.Inputs), + Outputs: toOutputs(tx.Outputs), + OutputsData: toBytesArray(tx.OutputsData), + Witnesses: toBytesArray(tx.Witnesses), + } +} + +func toCellDeps(deps []cellDep) []*types.CellDep { + result := make([]*types.CellDep, len(deps)) + for i := 0; i < len(deps); i++ { + dep := deps[i] + result[i] = &types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: dep.OutPoint.TxHash, + Index: uint(dep.OutPoint.Index), + }, + DepType: dep.DepType, + } + } + return result +} + +func toInputs(inputs []cellInput) []*types.CellInput { + result := make([]*types.CellInput, len(inputs)) + for i := 0; i < len(inputs); i++ { + input := inputs[i] + result[i] = &types.CellInput{ + Since: uint64(input.Since), + PreviousOutput: &types.OutPoint{ + TxHash: input.PreviousOutput.TxHash, + Index: uint(input.PreviousOutput.Index), + }, + } + } + return result +} + +func toOutputs(outputs []cellOutput) []*types.CellOutput { + result := make([]*types.CellOutput, len(outputs)) + for i := 0; i < len(outputs); i++ { + output := outputs[i] + result[i] = &types.CellOutput{ + Capacity: uint64(output.Capacity), + Lock: &types.Script{ + CodeHash: output.Lock.CodeHash, + HashType: output.Lock.HashType, + Args: output.Lock.Args, + }, + } + if output.Type != nil { + result[i].Type = &types.Script{ + CodeHash: output.Type.CodeHash, + HashType: output.Type.HashType, + Args: output.Type.Args, + } + } + } + return result +} + +func toBytesArray(bytes []hexutil.Bytes) [][]byte { + result := make([][]byte, len(bytes)) + for i, data := range bytes { + result[i] = data + } + return result +} diff --git a/mercury/model/resp/transcation_resp.go b/mercury/model/resp/transcation_resp.go new file mode 100644 index 00000000..c479f6b5 --- /dev/null +++ b/mercury/model/resp/transcation_resp.go @@ -0,0 +1,44 @@ +package resp + +import ( + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/nervosnetwork/ckb-sdk-go/types" +) + +type transactionResp struct { + Version hexutil.Uint `json:"version"` + Hash types.Hash `json:"hash"` + CellDeps []cellDep `json:"cell_deps"` + HeaderDeps []types.Hash `json:"header_deps"` + Inputs []cellInput `json:"inputs"` + Outputs []cellOutput `json:"outputs"` + OutputsData []hexutil.Bytes `json:"outputs_data"` + Witnesses []hexutil.Bytes `json:"witnesses"` +} + +type cellDep struct { + OutPoint outPoint `json:"out_point"` + DepType types.DepType `json:"dep_type"` +} + +type outPoint struct { + TxHash types.Hash `json:"tx_hash"` + Index hexutil.Uint `json:"index"` +} + +type cellInput struct { + Since hexutil.Uint64 `json:"since"` + PreviousOutput outPoint `json:"previous_output"` +} + +type cellOutput struct { + Capacity hexutil.Uint64 `json:"capacity"` + Lock *script `json:"lock"` + Type *script `json:"type"` +} + +type script struct { + CodeHash types.Hash `json:"code_hash"` + HashType types.ScriptHashType `json:"hash_type"` + Args hexutil.Bytes `json:"args"` +} diff --git a/mercury/model/source/source.go b/mercury/model/source/source.go new file mode 100644 index 00000000..6e58a509 --- /dev/null +++ b/mercury/model/source/source.go @@ -0,0 +1,6 @@ +package source + +const ( + Unconstrained = "owned" + Fleeting = "claimable" +) diff --git a/mercury/model/transfer_payload.go b/mercury/model/transfer_payload.go new file mode 100644 index 00000000..6d97940e --- /dev/null +++ b/mercury/model/transfer_payload.go @@ -0,0 +1,72 @@ +package model + +type TransferPayload struct { + UdtHash string `json:"udt_hash,omitempty"` + From *FromAccount `json:"from"` + Items []*TransferItem `json:"items"` + Change string `json:"change,omitempty"` + Fee uint `json:"fee"` +} + +type FromAccount struct { + Idents []string `json:"idents"` + Source string `json:"source"` +} + +type TransferItem struct { + To *ToAccount `json:"to"` + Amount uint `json:"amount"` +} + +type ToAccount struct { + Ident string `json:"ident"` + Action string `json:"action"` +} + +type TransferBuilder struct { + UdtHash string `json:"udt_hash,omitempty"` + From *FromAccount `json:"from"` + Items []*TransferItem `json:"items"` + Change string `json:"change,omitempty"` + Fee uint `json:"fee"` +} + +func (builder *TransferBuilder) AddUdtHash(udtHash string) { + builder.UdtHash = udtHash +} + +func (builder *TransferBuilder) AddFrom(idents []string, source string) { + form := &FromAccount{ + Idents: idents, + Source: source, + } + builder.From = form +} + +func (builder *TransferBuilder) AddItem(ident, action string, amount uint) { + to := &ToAccount{ + Ident: ident, + Action: action} + item := &TransferItem{Amount: amount} + item.To = to + builder.Items = append(builder.Items, item) +} + +func (builder *TransferBuilder) AddChange(change string) { + builder.Change = change +} + +func (builder *TransferBuilder) AddFee(fee uint) { + builder.Fee = fee +} + +func (builder *TransferBuilder) Build() *TransferPayload { + return &TransferPayload{ + builder.UdtHash, + builder.From, + builder.Items, + builder.Change, + builder.Fee, + } + +} diff --git a/mercury/test/action_test.go b/mercury/test/action_test.go new file mode 100644 index 00000000..2c2370f6 --- /dev/null +++ b/mercury/test/action_test.go @@ -0,0 +1,139 @@ +package test + +import ( + "context" + "fmt" + "github.com/nervosnetwork/ckb-sdk-go/crypto/secp256k1" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/action" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/resp" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/source" + "github.com/nervosnetwork/ckb-sdk-go/mercury/test/constant" + "github.com/nervosnetwork/ckb-sdk-go/transaction" + "github.com/nervosnetwork/ckb-sdk-go/types" + "testing" +) + +func TestTransferCompletionCkbWithPayByFrom(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + transferPayload := getTransferPayload(constant.TEST_ADDRESS0, constant.TEST_ADDRESS4, "", action.Pay_by_from) + transferCompletion, err := mercuryApi.BuildTransferTransaction(transferPayload) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func TestTransferCompletionSudtWithPayByFrom(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + transferPayload := getTransferPayload(constant.TEST_ADDRESS0, constant.TEST_ADDRESS4, "0xf21e7350fa9518ed3cbb008e0e8c941d7e01a12181931d5608aa366ee22228bd", action.Pay_by_from) + transferCompletion, err := mercuryApi.BuildTransferTransaction(transferPayload) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func TestTransferCompletionCkbWithLendByFrom(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + + transferPayload := getTransferPayload(constant.TEST_ADDRESS1, constant.TEST_ADDRESS2, "", action.Lend_by_from) + _, err := mercuryApi.BuildTransferTransaction(transferPayload) + if err != nil && err.Error() != "The transaction does not support ckb" { + panic(err) + } + +} + +func TestTransferCompletionSudtWithLendByFrom(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + transferPayload := getTransferPayload(constant.TEST_ADDRESS1, constant.TEST_ADDRESS2, "0xf21e7350fa9518ed3cbb008e0e8c941d7e01a12181931d5608aa366ee22228bd", action.Lend_by_from) + transferCompletion, err := mercuryApi.BuildTransferTransaction(transferPayload) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func TestTransferCompletionCkbWithPayByTo(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + + transferPayload := getTransferPayload(constant.TEST_ADDRESS1, constant.TEST_ADDRESS2, "", action.Pay_by_to) + _, err := mercuryApi.BuildTransferTransaction(transferPayload) + if err != nil && err.Error() != "The transaction does not support ckb" { + t.Error(err) + } +} + +func TestTransferCompletionSudtWithPayByTo(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + transferPayload := getTransferPayload(constant.TEST_ADDRESS1, constant.TEST_ADDRESS2, "0xf21e7350fa9518ed3cbb008e0e8c941d7e01a12181931d5608aa366ee22228bd", action.Pay_by_to) + transferCompletion, err := mercuryApi.BuildTransferTransaction(transferPayload) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func getTransferPayload(from, to, udtHash, action string) *model.TransferPayload { + builder := new(model.TransferBuilder) + builder.AddUdtHash(udtHash) + builder.AddFrom([]string{from}, source.Unconstrained) + builder.AddItem(to, action, 100) + builder.AddFee(10000000) + + return builder.Build() +} + +func sign(transferCompletion *resp.TransferCompletionResponse) *types.Transaction { + transferCompletion.GetScriptGroup() + tx := transferCompletion.GetTransaction() + scriptGroups := transferCompletion.GetScriptGroup() + for _, group := range scriptGroups { + key, _ := secp256k1.HexToKey(constant.GetKey(group.PubKey)) + if err := transaction.SingleSignTransaction(tx, group.Group, group.WitnessArgs, key); err != nil { + panic(err) + } + } + return tx +} diff --git a/mercury/test/balance_test.go b/mercury/test/balance_test.go new file mode 100644 index 00000000..4eebee4f --- /dev/null +++ b/mercury/test/balance_test.go @@ -0,0 +1,25 @@ +package test + +import ( + "fmt" + "github.com/nervosnetwork/ckb-sdk-go/mercury/test/constant" + "testing" +) + +func TestGetBalance(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + balance, err := mercuryApi.GetBalance(nil, constant.TEST_ADDRESS0) + if err != nil { + t.Error(err) + } + fmt.Println(balance.Unconstrained) +} + +func TestGetSudtBalance(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + balance, err := mercuryApi.GetBalance("0xf21e7350fa9518ed3cbb008e0e8c941d7e01a12181931d5608aa366ee22228bd", constant.TEST_ADDRESS0) + if err != nil { + t.Error(err) + } + fmt.Println(balance.Unconstrained) +} diff --git a/mercury/test/constant/address_with_key_holder.go b/mercury/test/constant/address_with_key_holder.go new file mode 100644 index 00000000..e9df0bcb --- /dev/null +++ b/mercury/test/constant/address_with_key_holder.go @@ -0,0 +1,31 @@ +package constant + +const ( + TEST_ADDRESS0 = "ckt1qyq28wze3cw48ek9az0g4jmtfs6d8td38u4s6hp2s0" + TEST_ADDRESS1 = "ckt1qyq27z6pccncqlaamnh8ttapwn260egnt67ss2cwvz" + TEST_ADDRESS2 = "ckt1qyqqtg06h75ymw098r3w0l3u4xklsj04tnsqctqrmc" + TEST_ADDRESS3 = "ckt1qyqzqfj8lmx9h8vvhk62uut8us844v0yh2hsnqvvgc" + TEST_ADDRESS4 = "ckt1qyqg88ccqm59ksxp85788pnqg4rkejdgcg2qxcu2qf" + TEST_KEY0 = "6fc935dad260867c749cf1ba6602d5f5ed7fb1131f1beb65be2d342e912eaafe" + TEST_KEY1 = "9d8ca87d75d150692211fa62b0d30de4d1ee6c530d5678b40b8cedacf0750d0f" + TEST_KEY2 = "88a09e06735d89452552e359a052315ab5130dc2e4d864ae3eed21d6505b2f67" + TEST_KEY3 = "2d4cf0546a1dc93092ad56f2e18fbe6e41ee477d9dec0575cf43b69740ce9f74" + TEST_KEY4 = "5e46fdbb6ffd86d232080dc71f24b60df2a119e0102ca45a7c165472de14c104" +) + +func GetKey(address string) string { + switch address { + case TEST_ADDRESS0: + return TEST_KEY0 + case TEST_ADDRESS1: + return TEST_KEY1 + case TEST_ADDRESS2: + return TEST_KEY2 + case TEST_ADDRESS3: + return TEST_KEY3 + case TEST_ADDRESS4: + return TEST_KEY4 + default: + return "" + } +} diff --git a/mercury/test/constant/ckb_node_factory.go b/mercury/test/constant/ckb_node_factory.go new file mode 100644 index 00000000..569e5dc1 --- /dev/null +++ b/mercury/test/constant/ckb_node_factory.go @@ -0,0 +1,18 @@ +package constant + +import "github.com/nervosnetwork/ckb-sdk-go/rpc" + +const NODE_URL = "http://8.210.169.63:8114" + +type CkbNodeFactory struct { + clent rpc.Client +} + +func GetCkbNodeInstance() rpc.Client { + client, err := rpc.Dial(NODE_URL) + if err != nil { + panic(err) + } + + return client +} diff --git a/mercury/test/constant/mercury_api_factory.go b/mercury/test/constant/mercury_api_factory.go new file mode 100644 index 00000000..64331d15 --- /dev/null +++ b/mercury/test/constant/mercury_api_factory.go @@ -0,0 +1,18 @@ +package constant + +import "github.com/nervosnetwork/ckb-sdk-go/mercury" + +const MERCURY_URL = "http://8.210.169.63:8116" + +type MercuryApiFactory struct { + clent mercury.MercuryApi +} + +func GetMercuryApiInstance() mercury.MercuryApi { + api, err := mercury.NewMercuryApi(MERCURY_URL) + if err != nil { + panic(err) + } + + return api +} diff --git a/mercury/test/create_wallet_test.go b/mercury/test/create_wallet_test.go new file mode 100644 index 00000000..0751d20a --- /dev/null +++ b/mercury/test/create_wallet_test.go @@ -0,0 +1,41 @@ +package test + +import ( + "context" + "fmt" + "github.com/nervosnetwork/ckb-sdk-go/crypto/secp256k1" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model" + "github.com/nervosnetwork/ckb-sdk-go/mercury/test/constant" + "github.com/nervosnetwork/ckb-sdk-go/transaction" + "testing" +) + +func TestCreateWallet(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + builder := new(model.CreateWalletPayload) + builder.AddIdent(constant.TEST_ADDRESS4) + builder.AddFee(1000000) + builder.AddInfo("0xf21e7350fa9518ed3cbb008e0e8c941d7e01a12181931d5608aa366ee22228bd") + + creationTransaction, err := mercuryApi.BuildWalletCreationTransaction(builder.Build()) + if err != nil { + t.Error(err) + } + + creationTransaction.GetScriptGroup() + tx := creationTransaction.GetTransaction() + scriptGroups := creationTransaction.GetScriptGroup() + for _, group := range scriptGroups { + key, _ := secp256k1.HexToKey("2d4cf0546a1dc93092ad56f2e18fbe6e41ee477d9dec0575cf43b69740ce9f74") + err = transaction.SingleSignTransaction(tx, group.Group, group.WitnessArgs, key) + } + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} diff --git a/mercury/test/transfer_completion_test.go b/mercury/test/transfer_completion_test.go new file mode 100644 index 00000000..5c69a2a8 --- /dev/null +++ b/mercury/test/transfer_completion_test.go @@ -0,0 +1,109 @@ +package test + +import ( + "context" + "fmt" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/action" + "github.com/nervosnetwork/ckb-sdk-go/mercury/model/source" + "github.com/nervosnetwork/ckb-sdk-go/mercury/test/constant" + "testing" +) + +func TestSingleFromSingleTo(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + builder := new(model.TransferBuilder) + builder.AddFrom([]string{constant.TEST_ADDRESS1}, source.Unconstrained) + builder.AddItem(constant.TEST_ADDRESS2, action.Pay_by_from, 100) + builder.AddFee(10000000) + + transferCompletion, err := mercuryApi.BuildTransferTransaction(builder.Build()) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func TestSingleFromMultiTo(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + builder := new(model.TransferBuilder) + builder.AddFrom([]string{constant.TEST_ADDRESS1}, source.Unconstrained) + builder.AddItem(constant.TEST_ADDRESS2, action.Pay_by_from, 100) + builder.AddItem(constant.TEST_ADDRESS3, action.Pay_by_from, 100) + builder.AddFee(10000000) + + transferCompletion, err := mercuryApi.BuildTransferTransaction(builder.Build()) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func TestMultiFromSingleTo(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + builder := new(model.TransferBuilder) + builder.AddFrom([]string{constant.TEST_ADDRESS1, constant.TEST_ADDRESS2}, source.Unconstrained) + builder.AddItem(constant.TEST_ADDRESS3, action.Pay_by_from, 100) + builder.AddFee(10000000) + + transferCompletion, err := mercuryApi.BuildTransferTransaction(builder.Build()) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} + +func TestMultiFromMultiTo(t *testing.T) { + mercuryApi := constant.GetMercuryApiInstance() + ckbNode := constant.GetCkbNodeInstance() + + builder := new(model.TransferBuilder) + builder.AddFrom([]string{constant.TEST_ADDRESS1, constant.TEST_ADDRESS2}, source.Unconstrained) + builder.AddItem(constant.TEST_ADDRESS3, action.Pay_by_from, 100) + builder.AddItem(constant.TEST_ADDRESS4, action.Pay_by_from, 100) + builder.AddFee(10000000) + + transferCompletion, err := mercuryApi.BuildTransferTransaction(builder.Build()) + if err != nil { + t.Error(err) + } + + tx := sign(transferCompletion) + + hash, err := ckbNode.SendTransaction(context.Background(), tx) + if err != nil { + t.Error(err) + } + + fmt.Println(hash) +} diff --git a/test/mock/rpc/mock_rpc.go b/test/mock/rpc/mock_rpc.go index 50caafdb..2be14bec 100644 --- a/test/mock/rpc/mock_rpc.go +++ b/test/mock/rpc/mock_rpc.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: client.go +// source: client.go // Package mock_rpc is a generated GoMock package. package mock_rpc