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