OSDN Git Service

update
[bytom/shuttle.git] / cmd / swap / commands.go
1 package main
2
3 import (
4         "bufio"
5         "encoding/hex"
6         "fmt"
7         "os"
8         "strconv"
9
10         "github.com/equity/compiler"
11         equ "github.com/equity/equity/util"
12         "github.com/spf13/cobra"
13
14         "github.com/shuttle/swap"
15 )
16
17 func init() {
18         // deploy contract arguments
19         deployTradeoffCmd.PersistentFlags().Uint64Var(&txFee, "txFee", 40000000, "contract transaction fee")
20         deployTradeoffCmd.PersistentFlags().StringVar(&assetRequested, "assetRequested", "", "tradeoff contract paramenter with requested assetID")
21         deployTradeoffCmd.PersistentFlags().Uint64Var(&amountRequested, "amountRequested", 0, "tradeoff contract paramenter with requested amount")
22         deployTradeoffCmd.PersistentFlags().StringVar(&seller, "seller", "", "tradeoff contract paramenter with seller control-program")
23         deployTradeoffCmd.PersistentFlags().StringVar(&cancelKey, "cancelKey", "", "tradeoff contract paramenter with seller pubkey for cancelling the contract")
24         deployTradeoffCmd.PersistentFlags().StringVar(&assetLocked, "assetLocked", "", "tradeoff contract locked value with assetID")
25         deployTradeoffCmd.PersistentFlags().Uint64Var(&amountLocked, "amountLocked", 0, "tradeoff contract locked value with amount")
26         deployTradeoffCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
27         deployTradeoffCmd.PersistentFlags().StringVar(&port, "port", "9888", "network port")
28
29         // deploy HTLC contract arguments
30         deployHTLCCmd.PersistentFlags().Uint64Var(&txFee, "txFee", 40000000, "contract transaction fee")
31         deployHTLCCmd.PersistentFlags().StringVar(&senderPublicKey, "sender", "", "HTLC contract paramenter with sender PublicKey")
32         deployHTLCCmd.PersistentFlags().StringVar(&recipientPublicKey, "recipient", "", "HTLC contract paramenter with recipientPublicKey")
33         deployHTLCCmd.PersistentFlags().Uint64Var(&blockHeight, "blockHeight", 0, "HTLC contract locked value with blockHeight")
34         deployHTLCCmd.PersistentFlags().StringVar(&hash, "hash", "", "HTLC contract locked value with hash")
35         deployHTLCCmd.PersistentFlags().StringVar(&assetLocked, "assetLocked", "", "HTLC contract locked value with assetID")
36         deployHTLCCmd.PersistentFlags().Uint64Var(&amountLocked, "amountLocked", 0, "HTLC contract locked value with amount")
37         deployHTLCCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
38         deployHTLCCmd.PersistentFlags().StringVar(&port, "port", "9888", "network port")
39
40         // call contract arguments
41         callTradeoffCmd.PersistentFlags().Uint64Var(&txFee, "txFee", 40000000, "contract transaction fee")
42         callTradeoffCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
43         callTradeoffCmd.PersistentFlags().StringVar(&port, "port", "9888", "network port")
44
45         // call HTLC contract arguments
46         callHTLCCmd.PersistentFlags().Uint64Var(&txFee, "txFee", 40000000, "contract transaction fee")
47         callHTLCCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
48         callHTLCCmd.PersistentFlags().StringVar(&port, "port", "9888", "network port")
49
50         // cancel tradeoff contract arguments
51         cancelTradeoffCmd.PersistentFlags().Uint64Var(&txFee, "txFee", 40000000, "contract transaction fee")
52         cancelTradeoffCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
53         cancelTradeoffCmd.PersistentFlags().StringVar(&port, "port", "9888", "network port")
54
55         // cancel HTLC contract arguments
56         cancelHTLCCmd.PersistentFlags().Uint64Var(&txFee, "txFee", 40000000, "contract transaction fee")
57         cancelHTLCCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
58         cancelHTLCCmd.PersistentFlags().StringVar(&port, "port", "9888", "network port")
59
60         // compile contract locally
61         equityCmd.PersistentFlags().BoolVar(&bin, strBin, false, "Binary of the contracts in hex.")
62         equityCmd.PersistentFlags().BoolVar(&shift, strShift, false, "Function shift of the contracts.")
63         equityCmd.PersistentFlags().BoolVar(&instance, strInstance, false, "Object of the Instantiated contracts.")
64         equityCmd.PersistentFlags().BoolVar(&ast, strAst, false, "AST of the contracts.")
65         equityCmd.PersistentFlags().BoolVar(&version, strVersion, false, "Version of equity compiler.")
66
67         // build deploy contract tx
68         buildTxCmd.PersistentFlags().StringVar(&ip, "ip", "127.0.0.1", "network address")
69         buildTxCmd.PersistentFlags().StringVar(&port, "port", "3000", "network port")
70 }
71
72 var (
73         txFee = uint64(0)
74         ip    = "127.0.0.1"
75         port  = "3000"
76
77         // contract paramenters
78         assetRequested  = ""
79         amountRequested = uint64(0)
80         seller          = ""
81         cancelKey       = ""
82
83         // contract locked value
84         assetLocked  = ""
85         amountLocked = uint64(0)
86
87         // unlock contract paramenters
88         contractUTXOID = ""
89         buyer          = ""
90 )
91
92 var (
93         senderPublicKey    = ""
94         recipientPublicKey = ""
95         blockHeight        = uint64(0)
96         hash               = ""
97         preimage           = ""
98 )
99
100 var (
101         strBin      string = "bin"
102         strShift    string = "shift"
103         strInstance string = "instance"
104         strAst      string = "ast"
105         strVersion  string = "version"
106 )
107
108 var (
109         bin      = false
110         shift    = false
111         instance = false
112         ast      = false
113         version  = false
114 )
115
116 var deployTradeoffCmd = &cobra.Command{
117         Use:   "deployTradeoff <accountID> <password> [contract flags(paramenters and locked value)] [txFee flag] [URL flags(ip and port)]",
118         Short: "deploy tradeoff contract",
119         Args:  cobra.ExactArgs(2),
120         Run: func(cmd *cobra.Command, args []string) {
121                 accountInfo := swap.AccountInfo{
122                         AccountID: args[0],
123                         Password:  args[1],
124                         TxFee:     txFee,
125                 }
126                 if len(accountInfo.AccountID) == 0 || len(accountInfo.Password) == 0 {
127                         fmt.Println("The part field of the structure AccountInfo is empty:", accountInfo)
128                         os.Exit(0)
129                 }
130
131                 contractArgs := swap.ContractArgs{
132                         AssetAmount: swap.AssetAmount{
133                                 Asset:  assetRequested,
134                                 Amount: amountRequested,
135                         },
136                         Seller:    seller,
137                         CancelKey: cancelKey,
138                 }
139                 if len(contractArgs.Asset) == 0 || contractArgs.Amount == uint64(0) || len(contractArgs.Seller) == 0 || len(contractArgs.CancelKey) == 0 {
140                         fmt.Println("The part field of the structure ContractArgs is empty:", contractArgs)
141                         os.Exit(0)
142                 }
143
144                 contractValue := swap.AssetAmount{
145                         Asset:  assetLocked,
146                         Amount: amountLocked,
147                 }
148                 if len(contractValue.Asset) == 0 || contractValue.Amount == uint64(0) {
149                         fmt.Println("The part field of the structure ContractValue AssetAmount is empty:", contractValue)
150                         os.Exit(0)
151                 }
152
153                 server := &swap.Server{
154                         IP:   ip,
155                         Port: port,
156                 }
157
158                 contractUTXOID, err := swap.DeployTradeoffContract(server, accountInfo, contractArgs, contractValue)
159                 if err != nil {
160                         fmt.Println(err)
161                         os.Exit(0)
162                 }
163                 fmt.Println("--> contractUTXOID:", contractUTXOID)
164         },
165 }
166
167 var buildTxCmd = &cobra.Command{
168         Use:   "build <guid> <outputID> <lockedAsset> <contractProgram> <lockedAmount> [URL flags(ip and port)]",
169         Short: "build contract",
170         Args:  cobra.ExactArgs(5),
171         Run: func(cmd *cobra.Command, args []string) {
172                 guid := args[0]
173                 if len(guid) == 0 {
174                         fmt.Println("The part field of guid is invalid:", guid)
175                         os.Exit(0)
176                 }
177
178                 outputID := args[1]
179                 if _, err := hex.DecodeString(outputID); err != nil || len(outputID) != 64 {
180                         fmt.Println("The part field of outputID is invalid:", outputID)
181                         os.Exit(0)
182                 }
183
184                 lockedAsset := args[2]
185                 if _, err := hex.DecodeString(lockedAsset); err != nil || len(lockedAsset) != 64 {
186                         fmt.Println("The part field of lockedAsset is invalid:", lockedAsset)
187                         os.Exit(0)
188                 }
189
190                 contractProgram := args[3]
191                 if _, err := hex.DecodeString(contractProgram); err != nil || len(contractProgram) == 0 {
192                         fmt.Println("The part field of contractProgram is invalid:", contractProgram)
193                         os.Exit(0)
194                 }
195
196                 lockedAmount, err := strconv.ParseUint(args[4], 10, 64)
197                 if err != nil {
198                         fmt.Println("parse locked amount err:", err)
199                         os.Exit(0)
200                 }
201
202                 server := &swap.Server{
203                         IP:   ip,
204                         Port: port,
205                 }
206
207                 res, err := swap.BuildTx(server, guid, outputID, lockedAsset, contractProgram, lockedAmount)
208                 if err != nil {
209                         fmt.Println("build tx err:", err)
210                         os.Exit(0)
211                 }
212
213                 fmt.Println("build tx result:", res)
214         },
215 }
216
217 var callTradeoffCmd = &cobra.Command{
218         Use:   "callTradeoff <accountID> <password> <buyer-program> <contractUTXOID> [txFee flag] [URL flags(ip and port)]",
219         Short: "call tradeoff contract for asset swapping",
220         Args:  cobra.ExactArgs(4),
221         Run: func(cmd *cobra.Command, args []string) {
222                 accountInfo := swap.AccountInfo{
223                         AccountID: args[0],
224                         Password:  args[1],
225                         Receiver:  args[2],
226                         TxFee:     txFee,
227                 }
228                 if len(accountInfo.AccountID) == 0 || len(accountInfo.Password) == 0 || len(accountInfo.Receiver) == 0 {
229                         fmt.Println("The part field of the structure AccountInfo is empty:", accountInfo)
230                         os.Exit(0)
231                 }
232
233                 contractUTXOID := args[3]
234                 if len(contractUTXOID) == 0 {
235                         fmt.Println("contract utxoID is empty:", contractUTXOID)
236                         os.Exit(0)
237                 }
238
239                 server := &swap.Server{
240                         IP:   ip,
241                         Port: port,
242                 }
243
244                 txID, err := swap.CallTradeoffContract(server, accountInfo, contractUTXOID)
245                 if err != nil {
246                         fmt.Println(err)
247                         os.Exit(0)
248                 }
249                 fmt.Println("--> txID:", txID)
250         },
251 }
252
253 var cancelTradeoffCmd = &cobra.Command{
254         Use:   "cancelTradeoff <accountID> <password> <redeem-program> <contractUTXOID> [txFee flag] [URL flags(ip and port)]",
255         Short: "cancel tradeoff contract for asset swapping",
256         Args:  cobra.ExactArgs(4),
257         Run: func(cmd *cobra.Command, args []string) {
258                 accountInfo := swap.AccountInfo{
259                         AccountID: args[0],
260                         Password:  args[1],
261                         Receiver:  args[2],
262                         TxFee:     txFee,
263                 }
264                 if len(accountInfo.AccountID) == 0 || len(accountInfo.Password) == 0 || len(accountInfo.Receiver) == 0 {
265                         fmt.Println("The part field of the structure AccountInfo is empty:", accountInfo)
266                         os.Exit(0)
267                 }
268
269                 contractUTXOID := args[3]
270                 if len(contractUTXOID) == 0 {
271                         fmt.Println("contract utxoID is empty:", contractUTXOID)
272                         os.Exit(0)
273                 }
274
275                 server := &swap.Server{
276                         IP:   ip,
277                         Port: port,
278                 }
279
280                 txID, err := swap.CancelTradeoffContract(server, accountInfo, contractUTXOID)
281                 if err != nil {
282                         fmt.Println(err)
283                         os.Exit(0)
284                 }
285                 fmt.Println("--> txID:", txID)
286         },
287 }
288
289 var deployHTLCCmd = &cobra.Command{
290         Use:   "deployHTLC <accountID> <password> [contract flags(paramenters and locked value)] [txFee flag] [URL flags(ip and port)]",
291         Short: "deploy HTLC contract",
292         Args:  cobra.ExactArgs(2),
293         Run: func(cmd *cobra.Command, args []string) {
294                 account := swap.AccountInfo{
295                         AccountID: args[0],
296                         Password:  args[1],
297                         TxFee:     txFee,
298                 }
299                 if len(account.AccountID) == 0 || len(account.Password) == 0 {
300                         fmt.Println("The part field of the structure AccountInfo is empty:", account)
301                         os.Exit(0)
302                 }
303
304                 contractArgs := swap.HTLCContractArgs{
305                         SenderPublicKey:    senderPublicKey,
306                         RecipientPublicKey: recipientPublicKey,
307                         BlockHeight:        blockHeight,
308                         Hash:               hash,
309                 }
310                 if len(contractArgs.SenderPublicKey) == 0 || len(contractArgs.RecipientPublicKey) == 0 || contractArgs.BlockHeight == uint64(0) || len(contractArgs.Hash) == 0 {
311                         fmt.Println("The part field of the structure ContractArgs is empty:", contractArgs)
312                         os.Exit(0)
313                 }
314
315                 contractValue := swap.AssetAmount{
316                         Asset:  assetLocked,
317                         Amount: amountLocked,
318                 }
319                 if len(contractValue.Asset) == 0 || contractValue.Amount == uint64(0) {
320                         fmt.Println("The part field of the structure ContractValue AssetAmount is empty:", contractValue)
321                         os.Exit(0)
322                 }
323
324                 server := &swap.Server{
325                         IP:   ip,
326                         Port: port,
327                 }
328
329                 contractUTXOID, err := swap.DeployHTLCContract(server, account, contractValue, contractArgs)
330                 if err != nil {
331                         fmt.Println(err)
332                         os.Exit(0)
333                 }
334                 fmt.Println("--> contractUTXOID:", contractUTXOID)
335         },
336 }
337
338 var callHTLCCmd = &cobra.Command{
339         Use:   "callHTLC <accountID> <password> <buyer-program> <preimage> <contractUTXOID> [txFee flag] [URL flags(ip and port)]",
340         Short: "call HTLC contract for asset swapping",
341         Args:  cobra.ExactArgs(5),
342         Run: func(cmd *cobra.Command, args []string) {
343                 account := swap.AccountInfo{
344                         AccountID: args[0],
345                         Password:  args[1],
346                         Receiver:  args[2],
347                         TxFee:     txFee,
348                 }
349                 if len(account.AccountID) == 0 || len(account.Password) == 0 || len(account.Receiver) == 0 {
350                         fmt.Println("The part field of the structure Account is empty:", account)
351                         os.Exit(0)
352                 }
353
354                 contractUTXOID := args[4]
355                 if len(contractUTXOID) == 0 {
356                         fmt.Println("contract utxoID is empty:", contractUTXOID)
357                         os.Exit(0)
358                 }
359
360                 preimage := args[3]
361                 server := &swap.Server{
362                         IP:   ip,
363                         Port: port,
364                 }
365                 txID, err := swap.CallHTLCContract(server, account, contractUTXOID, preimage)
366                 if err != nil {
367                         fmt.Println(err)
368                         os.Exit(0)
369                 }
370                 fmt.Println("--> txID:", txID)
371         },
372 }
373
374 var cancelHTLCCmd = &cobra.Command{
375         Use:   "cancelHTLC <accountID> <password> <redeem-program> <contractUTXOID> [txFee flag] [URL flags(ip and port)]",
376         Short: "cancel HTLC contract for asset swapping",
377         Args:  cobra.ExactArgs(4),
378         Run: func(cmd *cobra.Command, args []string) {
379                 accountInfo := swap.AccountInfo{
380                         AccountID: args[0],
381                         Password:  args[1],
382                         Receiver:  args[2],
383                         TxFee:     txFee,
384                 }
385                 if len(accountInfo.AccountID) == 0 || len(accountInfo.Password) == 0 || len(accountInfo.Receiver) == 0 {
386                         fmt.Println("The part field of the structure AccountInfo is empty:", accountInfo)
387                         os.Exit(0)
388                 }
389
390                 contractUTXOID := args[3]
391                 if len(contractUTXOID) == 0 {
392                         fmt.Println("contract utxoID is empty:", contractUTXOID)
393                         os.Exit(0)
394                 }
395
396                 server := &swap.Server{
397                         IP:   ip,
398                         Port: port,
399                 }
400
401                 txID, err := swap.CancelHTLCContract(server, accountInfo, contractUTXOID)
402                 if err != nil {
403                         fmt.Println(err)
404                         os.Exit(0)
405                 }
406                 fmt.Println("--> txID:", txID)
407         },
408 }
409
410 var equityCmd = &cobra.Command{
411         Use:     "equity <input_file>",
412         Short:   "equity commandline compiler",
413         Example: "equity contract_name [contract_args...] --bin --instance",
414         Args:    cobra.RangeArgs(0, 100),
415         Run: func(cmd *cobra.Command, args []string) {
416                 if version {
417                         version := compiler.VersionWithCommit(compiler.GitCommit)
418                         fmt.Println("equity, the equity compiler commandline interface")
419                         fmt.Println("Version:", version)
420                         os.Exit(0)
421                 }
422
423                 if len(args) < 1 {
424                         cmd.Usage()
425                         os.Exit(0)
426                 }
427
428                 if err := handleCompiled(args); err != nil {
429                         os.Exit(-1)
430                 }
431         },
432 }
433
434 func handleCompiled(args []string) error {
435         contractFile, err := os.Open(args[0])
436         if err != nil {
437                 fmt.Printf("An error [%v] occurred on opening the file, please check whether the file exists or can be accessed.\n", err)
438                 return err
439         }
440         defer contractFile.Close()
441
442         reader := bufio.NewReader(contractFile)
443         contracts, err := compiler.Compile(reader)
444         if err != nil {
445                 fmt.Println("Compile contract failed:", err)
446                 return err
447         }
448
449         // Print the result for all contracts
450         for i, contract := range contracts {
451                 fmt.Printf("======= %v =======\n", contract.Name)
452                 if bin {
453                         fmt.Println("Binary:")
454                         fmt.Printf("%v\n\n", hex.EncodeToString(contract.Body))
455                 }
456
457                 if shift {
458                         fmt.Println("Clause shift:")
459                         clauseMap, err := equ.Shift(contract)
460                         if err != nil {
461                                 fmt.Println("Statistics contract clause shift error:", err)
462                                 return err
463                         }
464
465                         for clause, shift := range clauseMap {
466                                 fmt.Printf("    %s:  %v\n", clause, shift)
467                         }
468                         fmt.Printf("\nNOTE: \n    If the contract contains only one clause, Users don't need clause selector when unlock contract." +
469                                 "\n    Furthermore, there is no signification for ending clause shift except for display.\n\n")
470                 }
471
472                 if instance {
473                         if i != len(contracts)-1 {
474                                 continue
475                         }
476
477                         fmt.Println("Instantiated program:")
478                         if len(args)-1 < len(contract.Params) {
479                                 fmt.Printf("Error: The number of input arguments %d is less than the number of contract parameters %d\n", len(args)-1, len(contract.Params))
480                                 usage := fmt.Sprintf("Usage:\n  equity %s", args[0])
481                                 for _, param := range contract.Params {
482                                         usage = usage + " <" + param.Name + ">"
483                                 }
484                                 fmt.Printf("%s\n\n", usage)
485                                 return err
486                         }
487
488                         contractArgs, err := equ.ConvertArguments(contract, args[1:len(contract.Params)+1])
489                         if err != nil {
490                                 fmt.Println("Convert arguments into contract parameters error:", err)
491                                 return err
492                         }
493
494                         instantProg, err := equ.InstantiateContract(contract, contractArgs)
495                         if err != nil {
496                                 fmt.Println("Instantiate contract error:", err)
497                                 return err
498                         }
499                         fmt.Printf("%v\n\n", hex.EncodeToString(instantProg))
500                 }
501
502                 if ast {
503                         fmt.Println("Ast:")
504                         rawData, err := equ.JSONMarshal(contract, true)
505                         if err != nil {
506                                 fmt.Println("Marshal the struct of contract to json error:", err)
507                                 return err
508                         }
509                         fmt.Println(string(rawData))
510                 }
511         }
512
513         return nil
514 }