Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simulate Off-Chain via the CLI (from Andrew Lunde @ SAP) #158

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3f9c463
service_payment
andrewlunde Jun 2, 2021
2f78e8f
wallet pain
andrewlunde Jun 3, 2021
587b902
off-chain kinda working
andrewlunde Jun 4, 2021
d416ba5
Merge branch 'thetatoken:master' into master
andrewlunde Jun 4, 2021
21c0d95
Merge branch 'thetatoken:master' into master
andrewlunde Jun 7, 2021
6bef452
test batch.sh
andrewlunde Jun 7, 2021
8a9584b
better batch
andrewlunde Jun 8, 2021
4754b6f
echo on-chain
andrewlunde Jun 10, 2021
e330879
WSJ example
andrewlunde Jun 11, 2021
f931680
added next sequence
andrewlunde Jun 11, 2021
2c6b76d
mostly ThetaTeam's password handling
andrewlunde Jun 14, 2021
cb13d69
t push origin masterMerge branch 'thetatoken-master'
andrewlunde Jun 14, 2021
707c603
refactor pwFlag to passwordFlag
andrewlunde Jun 14, 2021
b33fdb7
refactor tweek
andrewlunde Jun 14, 2021
31e9542
refactor testing ok
andrewlunde Jun 14, 2021
8b7c671
Merge branch 'thetatoken:master' into master
andrewlunde Jun 22, 2021
6d2e653
Merge branch 'thetatoken:master' into master
andrewlunde Jul 6, 2021
b7acfcb
Merge branch 'thetatoken:master' into master
andrewlunde Jul 13, 2021
b22ded2
Merge branch 'thetatoken:master' into master
andrewlunde Jul 19, 2021
3b39fa6
output some values to help debug javascript libs
andrewlunde Jul 19, 2021
430e287
version
andrewlunde Jul 23, 2021
581899d
version
andrewlunde Jul 23, 2021
42ef577
ver again
andrewlunde Jul 23, 2021
8ff8109
modsum
andrewlunde Jul 23, 2021
bf0d209
theta: changes for v0.1.0
andrewlunde Jul 23, 2021
9fb63eb
Merge branch 'thetatoken:master' into master
andrewlunde Jul 27, 2021
ae9959e
Merge branch 'master' of github.com:andrewlunde/theta-protocol-ledger
andrewlunde Jul 28, 2021
dd7cc79
added debugging flag
andrewlunde Jul 28, 2021
1d7660d
Merge pull request #139 from andrewlunde/master
jieyilong Aug 15, 2021
980d2ec
Some code clean-up
jieyilong Aug 15, 2021
9562bbf
Code clean up
jieyilong Aug 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/thetacli/cmd/tx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var (
reserveFundInTFuelFlag string
reserveCollateralInTFuelFlag string
reserveSeqFlag uint64
paymentSeqFlag uint64
addressesFlag []string
percentagesFlag []string
valueFlag string
Expand All @@ -33,9 +34,13 @@ var (
sourceFlag string
holderFlag string
asyncFlag bool
onChainFlag bool
sourceSignatureFlag string
dryRunFlag bool
beneficiaryFlag string
splitBasisPointFlag uint64
passwordFlag string
debuggingFlag bool
)

// TxCmd represents the Tx command
Expand All @@ -48,6 +53,7 @@ var TxCmd = &cobra.Command{
func init() {
TxCmd.AddCommand(sendCmd)
TxCmd.AddCommand(reserveFundCmd)
TxCmd.AddCommand(servicePaymentCmd)
//TxCmd.AddCommand(releaseFundCmd) // No need for releaseFundCmd since auto-release is already implemented
TxCmd.AddCommand(splitRuleCmd)
TxCmd.AddCommand(smartContractCmd)
Expand Down
19 changes: 17 additions & 2 deletions cmd/thetacli/cmd/tx/reserve_fund.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tx

import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"

Expand All @@ -11,6 +12,7 @@ import (
"github.com/thetatoken/theta/ledger/types"
"github.com/thetatoken/theta/rpc"

// "github.com/ybbus/jsonrpc"
rpcc "github.com/ybbus/jsonrpc"
)

Expand Down Expand Up @@ -100,7 +102,20 @@ func doReserveFundCmd(cmd *cobra.Command, args []string) {
if res.Error != nil {
utils.Error("Server returned error: %v\n", res.Error)
}
fmt.Printf("Successfully broadcasted transaction.\n")
result := &rpc.BroadcastRawTransactionResult{}
err = res.GetObject(result)
if err != nil {
utils.Error("Failed to parse server response: %v\n", err)
}
formatted, err := json.MarshalIndent(result, "", " ")
if err != nil {
utils.Error("Failed to parse server response: %v\n", err)
}
//fmt.Printf("Successfully broadcasted transaction:\n%s\n", formatted)
// Verbose output makes parsing json difficult
fmt.Printf("%s\n", formatted)

//fmt.Printf("Successfully broadcasted transaction.\n")
}

func init() {
Expand All @@ -111,7 +126,7 @@ func init() {
reserveFundCmd.Flags().StringVar(&reserveCollateralInTFuelFlag, "collateral", "0", "TFuel amount as collateral")
reserveFundCmd.Flags().StringVar(&feeFlag, "fee", fmt.Sprintf("%dwei", types.MinimumTransactionFeeTFuelWeiJune2021), "Fee")
reserveFundCmd.Flags().Uint64Var(&durationFlag, "duration", 1000, "Reserve duration")
reserveFundCmd.Flags().StringSliceVar(&resourceIDsFlag, "resource_ids", []string{}, "Reserouce IDs")
reserveFundCmd.Flags().StringSliceVar(&resourceIDsFlag, "resource_ids", []string{}, "Resource IDs")
reserveFundCmd.Flags().StringVar(&walletFlag, "wallet", "soft", "Wallet type (soft|nano)")
reserveFundCmd.Flags().BoolVar(&asyncFlag, "async", false, "block until tx has been included in the blockchain")
reserveFundCmd.Flags().StringVar(&passwordFlag, "password", "", "password to unlock the wallet")
Expand Down
5 changes: 4 additions & 1 deletion cmd/thetacli/cmd/tx/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ func doSendCmd(cmd *cobra.Command, args []string) {
if err != nil {
utils.Error("Failed to parse server response: %v\n", err)
}
fmt.Printf("Successfully broadcasted transaction:\n%s\n", formatted)
// Verbose output makes parsing json difficult
//fmt.Printf("Successfully broadcasted transaction:\n%s\n", formatted)
// Verbose output makes parsing json difficult
fmt.Printf("%s\n", formatted)
}

func init() {
Expand Down
285 changes: 285 additions & 0 deletions cmd/thetacli/cmd/tx/service_payment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
package tx

import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/thetatoken/theta/cmd/thetacli/cmd/utils"
"github.com/thetatoken/theta/common"
"github.com/thetatoken/theta/crypto"
"github.com/thetatoken/theta/ledger/types"
"github.com/thetatoken/theta/rpc"
wtypes "github.com/thetatoken/theta/wallet/types"

"github.com/ybbus/jsonrpc"
rpcc "github.com/ybbus/jsonrpc"
)

// servicePaymentCmd represents the send command
// Example:
// thetacli tx service_payment --chain="privatenet" --from=2E833968E5bB786Ae419c4d13189fB081Cc43bab --to=9F1233798E905E173560071255140b4A8aBd3Ec6 --payment_seq=1 --reserve_seq=1 --resource_id=rid1000001
var servicePaymentCmd = &cobra.Command{
Use: "service_payment",
Short: "Make Service Payment from Reserve fund",
Example: `thetacli tx service_payment --chain="privatenet" --from=2E833968E5bB786Ae419c4d13189fB081Cc43bab --to=9F1233798E905E173560071255140b4A8aBd3Ec6 --payment_seq=1 --reserve_seq=1 --resource_id=rid1000001`,
Run: doServicePaymentCmd,
}

func doServicePaymentCmd(cmd *cobra.Command, args []string) {
var debugging = debuggingFlag
walletType := getWalletType(cmd)
if walletType == wtypes.WalletTypeSoft && len(fromFlag) == 0 {
utils.Error("The from address cannot be empty") // we don't need to specify the "from address" for hardware wallets
return
}

if len(toFlag) == 0 {
utils.Error("The to address cannot be empty")
return
}

if fromFlag == toFlag {
utils.Error("The from and to address cannot be identical")
return
}

var swallet wtypes.Wallet
//common.HexToAddress(addressStr)
var fromAddress = common.HexToAddress(fromFlag)
var twallet wtypes.Wallet
var toAddress = common.HexToAddress(toFlag)
var err error

if debugging {
fmt.Printf("fromAddress: %s\n", fromAddress)
fmt.Printf("toAddress: %s\n", toAddress)
fmt.Printf("passwordFlag: %s\n", passwordFlag)
}

if onChainFlag {
// if 1 == 1 {
twallet, toAddress, err = walletUnlockWithPath(cmd, toFlag, pathFlag, passwordFlag)
if err != nil || twallet == nil {
return
}
defer twallet.Lock(toAddress)
} else {
swallet, fromAddress, err = walletUnlockWithPath(cmd, fromFlag, pathFlag, passwordFlag)
if err != nil || swallet == nil {
return
}
defer swallet.Lock(fromAddress)
}

tfuel, ok := types.ParseCoinAmount(tfuelAmountFlag)
if !ok {
utils.Error("Failed to parse tfuel amount")
}

fee, ok := types.ParseCoinAmount(feeFlag)
if !ok {
utils.Error("Failed to parse fee")
}

if debugging {
fmt.Printf("tfuel: %d\n", tfuel)
fmt.Printf("fee: %d\n", fee)
}

sinput := types.TxInput{
Address: fromAddress,
Coins: types.Coins{
ThetaWei: new(big.Int).SetUint64(0),
//TFuelWei: new(big.Int).Add(tfuel, fee),
TFuelWei: tfuel,
//TFuelWei: new(big.Int).SetUint64(1),
},
Sequence: uint64(paymentSeqFlag),
//Signature:
}

tinput := types.TxInput{
Address: toAddress,
Coins: types.Coins{
ThetaWei: new(big.Int).SetUint64(0),
TFuelWei: tfuel,
//TFuelWei: new(big.Int).SetUint64(0),
},
//Sequence: uint64(paymentSeqFlag),
//Signature:
}

if debugging {
fmt.Printf("paymentSeqFlag: %d\n", paymentSeqFlag)
fmt.Printf("reserveSeqFlag: %d\n", reserveSeqFlag)
fmt.Printf("resourceIDFlag: %s\n", resourceIDFlag)
}

// See theta-protocol-ledger > ledger > types > tx.go : Line 522
servicePaymentTx := &types.ServicePaymentTx{
Fee: types.Coins{
ThetaWei: new(big.Int).SetUint64(0),
TFuelWei: fee,
},
Source: sinput,
Target: tinput,
PaymentSequence: paymentSeqFlag,
ReserveSequence: reserveSeqFlag,
ResourceID: resourceIDFlag,
}

// Set the Source Signature
if onChainFlag {
if debugging {
fmt.Printf("Set the Source Signature On-Chain\n")
}
//ssig, err := crypto.UnmarshalJSON([]byte(sourceSignatureFlag))
ssig, err := crypto.SignatureFromBytes(common.FromHex(sourceSignatureFlag))
if err != nil {
utils.Error("Failed to convert passed signature: %v\n", err)
}
servicePaymentTx.SetSourceSignature(ssig)
} else {
if debugging {
fmt.Printf("Set the Source Signature Off-Chain\n")
}
ssig, err := swallet.Sign(fromAddress, servicePaymentTx.SourceSignBytes(chainIDFlag))
if err != nil {
utils.Error("Failed to sign source transaction: %v\n", err)
}

//fmt.Printf("ssig: %s\n", ssig)
servicePaymentTx.SetSourceSignature(ssig)
if debugging {
fmt.Printf("Set the Source Signature Off-Chain Finished\n")
}
}

// Set the Target Signature
if onChainFlag {
if debugging {
fmt.Printf("Set the Target Signature On-Chain\n")
}
tsig, err := twallet.Sign(toAddress, servicePaymentTx.TargetSignBytes(chainIDFlag))
if err != nil {
utils.Error("Failed to sign target transaction: %v\n", err)
}
servicePaymentTx.SetTargetSignature(tsig)
} else {
if debugging {
fmt.Printf("Set the Target Signature Off-Chain\n")
}
tsig, err := crypto.SignatureFromBytes([]byte("unsigned"))
if err != nil {
utils.Error("Failed to convert passed signature: %v\n", err)
}
servicePaymentTx.SetTargetSignature(tsig)
if debugging {
fmt.Printf("Set the Target Signature Off-Chain Finished\n")
}
}

if debugging {
formatted, err := json.MarshalIndent(servicePaymentTx, "", " ")
if err != nil {
utils.Error("Failed to parse off-chain transaction: %v\n", err)
}
fmt.Printf("Off-Chain transaction:\n%s\n", formatted)
}

raw, err := types.TxToBytes(servicePaymentTx)
if err != nil {
utils.Error("Failed to encode transaction: %v\n", err)
}

if debugging {
fmt.Printf(" raw: %s\n", hex.EncodeToString(raw))
}

signedTx := hex.EncodeToString(raw)

if debugging {
fmt.Printf(" signedTx: %s\n", signedTx)
}

if onChainFlag {
if dryRunFlag {
if debugging {
formatted, err := json.MarshalIndent(servicePaymentTx, "", " ")
if err != nil {
utils.Error("Failed to parse off-chain transaction: %v\n", err)
}
//fmt.Printf("On-Chain transaction(dry-run):\n%s\n", formatted)
fmt.Printf("%s\n", formatted)
}
} else {

client := rpcc.NewRPCClient(viper.GetString(utils.CfgRemoteRPCEndpoint))

var res *jsonrpc.RPCResponse
if asyncFlag {
res, err = client.Call("theta.BroadcastRawTransactionAsync", rpc.BroadcastRawTransactionArgs{TxBytes: signedTx})
} else {
res, err = client.Call("theta.BroadcastRawTransaction", rpc.BroadcastRawTransactionArgs{TxBytes: signedTx})
}

if err != nil {
utils.Error("Failed to broadcast transaction: %v\n", err)
}
if res.Error != nil {
utils.Error("Server returned error: %v\n", res.Error)
}
result := &rpc.BroadcastRawTransactionResult{}
err = res.GetObject(result)
if err != nil {
utils.Error("Failed to parse server response: %v\n", err)
}

formatted, err := json.MarshalIndent(result, "", " ")
if err != nil {
utils.Error("Failed to parse server response: %v\n", err)
}
//fmt.Printf("Successfully broadcasted transaction:\n%s\n", formatted)
// Verbose output makes parsing json difficult
fmt.Printf("%s\n", formatted)
}
} else {
formatted, err := json.MarshalIndent(servicePaymentTx, "", " ")
if err != nil {
utils.Error("Failed to parse off-chain transaction: %v\n", err)
}
//fmt.Printf("Off-Chain transaction:\n%s\n", formatted)
fmt.Printf("%s\n", formatted)
}

}

func init() {
servicePaymentCmd.Flags().StringVar(&chainIDFlag, "chain", "", "Chain ID")
servicePaymentCmd.Flags().StringVar(&fromFlag, "from", "", "Address to send from")
servicePaymentCmd.Flags().StringVar(&toFlag, "to", "", "Address to send to")
servicePaymentCmd.Flags().StringVar(&pathFlag, "path", "", "Wallet derivation path")
servicePaymentCmd.Flags().Uint64Var(&paymentSeqFlag, "payment_seq", 0, "Payment sequence number of the transaction")
servicePaymentCmd.Flags().Uint64Var(&reserveSeqFlag, "reserve_seq", 0, "Reserve sequence number of the transaction")
servicePaymentCmd.Flags().StringVar(&tfuelAmountFlag, "tfuel", "0", "TFuel amount")
servicePaymentCmd.Flags().StringVar(&resourceIDFlag, "resource_id", "", "Corresponding resourceID")
servicePaymentCmd.Flags().StringVar(&feeFlag, "fee", fmt.Sprintf("%dwei", types.MinimumTransactionFeeTFuelWei), "Fee")
servicePaymentCmd.Flags().StringVar(&walletFlag, "wallet", "soft", "Wallet type (soft|nano|trezor)")
servicePaymentCmd.Flags().StringVar(&sourceSignatureFlag, "src_sig", "unsigned", "Source Signature from prior Off-Chain transaction")
servicePaymentCmd.Flags().BoolVar(&onChainFlag, "on_chain", false, "Process transaction On-Chain else return json of what would have been sent")
servicePaymentCmd.Flags().BoolVar(&asyncFlag, "async", false, "Block until tx has been included in the blockchain")
servicePaymentCmd.Flags().StringVar(&passwordFlag, "password", "", "password to unlock the wallet")
servicePaymentCmd.Flags().BoolVar(&dryRunFlag, "dry_run", false, "Dry Run(don't execute) the On-Chain transaction")
servicePaymentCmd.Flags().BoolVar(&debuggingFlag, "debugging", false, "Print verbose debugging output")

servicePaymentCmd.MarkFlagRequired("chain")
servicePaymentCmd.MarkFlagRequired("from")
servicePaymentCmd.MarkFlagRequired("to")
servicePaymentCmd.MarkFlagRequired("payment_seq")
servicePaymentCmd.MarkFlagRequired("reserve_seq")
servicePaymentCmd.MarkFlagRequired("resource_id")
}
4 changes: 3 additions & 1 deletion cmd/thetacli/cmd/tx/smart_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ func doSmartContractCmd(cmd *cobra.Command, args []string) {
if err != nil {
utils.Error("Failed to parse server response: %v\n", err)
}
fmt.Printf("Successfully broadcasted transaction:\n%s\n", formatted)
//fmt.Printf("Successfully broadcasted transaction:\n%s\n", formatted)
// Verbose output makes parsing json difficult
fmt.Printf("%s\n", formatted)
}

func init() {
Expand Down
Loading