github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/cmd/bytomcli/commands/template.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/bytom/bytom/errors"
     7  )
     8  
     9  const (
    10  	// contract TradeOffer's clause
    11  	clauseTrade      = "00000000"
    12  	clauseCancel     = "13000000"
    13  	tradeOfferEnding = "1a000000"
    14  
    15  	// contract Escrow's clause
    16  	clauseApprove = "00000000"
    17  	clauseReject  = "1a000000"
    18  	escrowEnding  = "28000000"
    19  
    20  	// contract LoanCollateral's clause
    21  	clauseRepay          = "00000000"
    22  	clauseDefault        = "1b000000"
    23  	loanCollateralEnding = "26000000"
    24  
    25  	// contract CallOption's clause
    26  	clauseExercise   string = "00000000"
    27  	clauseExpire     string = "20000000"
    28  	callOptionEnding string = "2c000000"
    29  )
    30  
    31  var (
    32  	errBadContractArguments = errors.New("bad contract arguments")
    33  )
    34  
    35  // common receiver template, the clause takes only one parameter without Signature in the contract that contains only one clause,
    36  // or the clause takes no parameters in the contract with multiple clauses. In addition, clause's statement like "lock payment with program" or "unlock value"
    37  var buildCommonRecvReqFmt = `
    38  	{"actions": [
    39  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
    40  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
    41  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
    42  	]}`
    43  
    44  var buildCommonRecvReqFmtByAlias = `
    45  	{"actions": [
    46  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
    47  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
    48  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
    49  	]}`
    50  
    51  // contract is LockWithPublicKey
    52  var buildLockWithPublicKeyReqFmt = `
    53  	{"actions": [
    54  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}}]},
    55  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
    56  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
    57  	]}`
    58  
    59  var buildLockWithPublicKeyReqFmtByAlias = `
    60  	{"actions": [
    61  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}}]},
    62  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
    63  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
    64  	]}`
    65  
    66  // contract is LockWithMultiSig
    67  var buildLockWithMultiSigReqFmt = `
    68  	{"actions": [
    69  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
    70  				{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}}]},
    71  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
    72  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
    73  	]}`
    74  
    75  var buildLockWithMultiSigReqFmtByAlias = `
    76  	{"actions": [
    77  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
    78  				{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}}]},
    79  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
    80  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
    81  	]}`
    82  
    83  // contract is LockWithPublicKeyHash
    84  var buildLockWithPublicKeyHashReqFmt = `
    85  	{"actions": [
    86  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}},
    87  				{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}}]},
    88  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
    89  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
    90  	]}`
    91  
    92  var buildLockWithPublicKeyHashReqFmtByAlias = `
    93  	{"actions": [
    94  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}},
    95  				{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}}]},
    96  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
    97  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
    98  	]}`
    99  
   100  // contract is TradeOffer's clause trade, the code of clause contains only two statement with "lock payment with program" and "unlock value"
   101  var buildTradeOfferClauseTradeReqFmt = `
   102  	{"actions": [
   103  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
   104  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
   105  		{"type": "spend_account", "asset_id": "%s", "amount": %s, "account_id": "%s"},
   106  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount":%s, "account_id": "%s"},
   107  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"}
   108  	]}`
   109  
   110  var buildTradeOfferClauseTradeReqFmtByAlias = `
   111  	{"actions": [
   112  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
   113  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
   114  		{"type": "spend_account", "asset_alias": "%s", "amount": %s, "account_alias": "%s"},
   115  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"},
   116  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"}
   117  	]}`
   118  
   119  // contract is TradeOffer's clause cancel
   120  var buildTradeOfferClauseCancelReqFmt = `
   121  	{"actions": [
   122  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
   123  				{"type": "data", "raw_data": {"value": "%s"}}]},
   124  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
   125  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
   126  	]}`
   127  
   128  var buildTradeOfferClauseCancelReqFmtByAlias = `
   129  	{"actions": [
   130  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
   131  				{"type": "data", "raw_data": {"value": "%s"}}]},
   132  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
   133  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
   134  	]}`
   135  
   136  // contract is Escrow
   137  var buildEscrowReqFmt = `
   138  	{"actions": [
   139  		{"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
   140  				{"type": "data", "raw_data": {"value": "%s"}}]},
   141  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
   142  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount":%s, "account_id": "%s"}
   143  	]}`
   144  
   145  var buildEscrowReqFmtByAlias = `
   146  	{"actions": [
   147  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
   148  				{"type": "data", "raw_data": {"value": "%s"}}]},
   149  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
   150  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
   151  	]}`
   152  
   153  // contract is LoanCollateral's clause repay, the code of clause contains only two statement with "lock payment with program" and "lock value with control_program"
   154  var buildLoanCollateralClauseRepayReqFmt = `
   155  	{"actions": [
   156  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
   157  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
   158  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
   159  		{"type": "spend_account", "asset_id": "%s", "amount": %s, "account_id": "%s"},
   160  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount":%s, "account_id": "%s"}
   161  	]}`
   162  
   163  var buildLoanCollateralClauseRepayReqFmtByAlias = `
   164  	{"actions": [
   165  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
   166  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
   167  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
   168  		{"type": "spend_account", "asset_alias": "%s", "amount": %s, "account_alias": "%s"},
   169  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
   170  	]}`
   171  
   172  // contract is CallOption's clause exercise, the code of clause contains only two statement with "lock payment with program" and "unlock value"
   173  var buildCallOptionClauseExerciseReqFmt = `
   174  	{"actions": [
   175  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
   176  				{"type": "data", "raw_data": {"value": "%s"}}]},
   177  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
   178  		{"type": "spend_account", "asset_id": "%s", "amount": %s, "account_id": "%s"},
   179  		{"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount":%s, "account_id": "%s"},
   180  		{"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"}
   181  	]}`
   182  
   183  var buildCallOptionClauseExerciseReqFmtByAlias = `
   184  	{"actions": [
   185  		{"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
   186  				{"type": "data", "raw_data": {"value": "%s"}}]},
   187  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
   188  		{"type": "spend_account", "asset_alias": "%s", "amount": %s, "account_alias": "%s"},
   189  		{"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"},
   190  		{"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"}
   191  	]}`
   192  
   193  // contract arguments
   194  type baseContractArg struct {
   195  	accountInfo string
   196  	assetInfo   string
   197  	amount      string
   198  	alias       bool
   199  	program     string
   200  	btmGas      string
   201  	outputID    string
   202  }
   203  
   204  type basePubInfo struct {
   205  	rootPub string
   206  	path1   string
   207  	path2   string
   208  }
   209  
   210  type innerContractArg struct {
   211  	innerAccountInfo string
   212  	innerAssetInfo   string
   213  	innerAmount      string
   214  	innerProgram     string
   215  }
   216  
   217  // addContractArgs add arguments for template contracts
   218  func addContractArgs(contractName string, baseArg baseContractArg, specArgs []string, usage string) (buildReqStr string, err error) {
   219  	switch contractName {
   220  	case "LockWithPublicKey":
   221  		if len(specArgs) != 3 {
   222  			err = errors.WithDetailf(errBadContractArguments, "%s <rootPub> <path1> <path2> [flags]\n", usage)
   223  			return
   224  		}
   225  
   226  		pubInfo := basePubInfo{
   227  			rootPub: specArgs[0],
   228  			path1:   specArgs[1],
   229  			path2:   specArgs[2],
   230  		}
   231  		buildReqStr = addLockWithPublicKeyArg(baseArg, pubInfo)
   232  
   233  	case "LockWithMultiSig":
   234  		if len(specArgs) != 6 {
   235  			err = errors.WithDetailf(errBadContractArguments, "%s <rootPub1> <path11> <path12> <rootPub2> <path21> <path22> [flags]\n", usage)
   236  			return
   237  		}
   238  
   239  		pubInfos := [2]basePubInfo{
   240  			{
   241  				rootPub: specArgs[0],
   242  				path1:   specArgs[1],
   243  				path2:   specArgs[2],
   244  			},
   245  			{
   246  				rootPub: specArgs[3],
   247  				path1:   specArgs[4],
   248  				path2:   specArgs[5],
   249  			},
   250  		}
   251  		buildReqStr = addLockWithMultiSigArg(baseArg, pubInfos)
   252  
   253  	case "LockWithPublicKeyHash":
   254  		if len(specArgs) != 4 {
   255  			err = errors.WithDetailf(errBadContractArguments, "%s <pubKey> <rootPub> <path1> <path2> [flags]\n", usage)
   256  			return
   257  		}
   258  
   259  		pubkey := specArgs[0]
   260  		pubInfo := basePubInfo{
   261  			rootPub: specArgs[1],
   262  			path1:   specArgs[2],
   263  			path2:   specArgs[3],
   264  		}
   265  		buildReqStr = addLockWithPublicKeyHashArg(baseArg, pubInfo, pubkey)
   266  
   267  	case "RevealPreimage":
   268  		if len(specArgs) != 1 {
   269  			err = errors.WithDetailf(errBadContractArguments, "%s <value> [flags]\n", usage)
   270  			return
   271  		}
   272  
   273  		value := specArgs[0]
   274  		buildReqStr = addRevealPreimageArg(baseArg, value)
   275  
   276  	case "TradeOffer":
   277  		switch {
   278  		case len(specArgs) <= 0:
   279  			err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> (<innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram>) | (<rootPub> <path1> <path2>) [flags]\n", usage)
   280  		case specArgs[0] == clauseTrade:
   281  			if len(specArgs) != 5 {
   282  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> [flags]\n", usage)
   283  				return
   284  			}
   285  
   286  			inner := &innerContractArg{
   287  				innerAccountInfo: specArgs[1],
   288  				innerAssetInfo:   specArgs[2],
   289  				innerAmount:      specArgs[3],
   290  				innerProgram:     specArgs[4],
   291  			}
   292  			buildReqStr, err = addTradeOfferArg(baseArg, clauseTrade, inner, nil)
   293  
   294  		case specArgs[0] == clauseCancel:
   295  			if len(specArgs) != 4 {
   296  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <rootPub> <path1> <path2> [flags]\n", usage)
   297  				return
   298  			}
   299  
   300  			pubInfo := &basePubInfo{
   301  				rootPub: specArgs[1],
   302  				path1:   specArgs[2],
   303  				path2:   specArgs[3],
   304  			}
   305  			buildReqStr, err = addTradeOfferArg(baseArg, clauseCancel, nil, pubInfo)
   306  
   307  		case specArgs[0] == tradeOfferEnding:
   308  			err = errors.WithDetailf(errBadContractArguments, "Clause ending was selected in contract %s, ending exit\n", contractName)
   309  		default:
   310  			err = errors.WithDetailf(errBadContractArguments, "selected clause [%s] error, contract %s's clause must in set [%s, %s, %s]\n",
   311  				specArgs[0], contractName, clauseTrade, clauseCancel, tradeOfferEnding)
   312  		}
   313  
   314  	case "Escrow":
   315  		switch {
   316  		case len(specArgs) <= 0:
   317  			err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <rootPub> <path1> <path2> <controlProgram> [flags]\n", usage)
   318  		case specArgs[0] == clauseApprove || specArgs[0] == clauseReject:
   319  			if len(specArgs) != 5 {
   320  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <rootPub> <path1> <path2> <controlProgram> [flags]\n", usage)
   321  				return
   322  			}
   323  
   324  			pubInfo := &basePubInfo{
   325  				rootPub: specArgs[1],
   326  				path1:   specArgs[2],
   327  				path2:   specArgs[3],
   328  			}
   329  			controlProgram := specArgs[4]
   330  			buildReqStr, err = addEscrowArg(baseArg, specArgs[0], pubInfo, controlProgram)
   331  
   332  		case specArgs[0] == escrowEnding:
   333  			err = errors.WithDetailf(errBadContractArguments, "Clause ending was selected in contract %s, ending exit\n", contractName)
   334  		default:
   335  			err = errors.WithDetailf(errBadContractArguments, "selected clause [%s] error, contract %s's clause must in set [%s, %s, %s]\n",
   336  				specArgs[0], contractName, clauseApprove, clauseReject, escrowEnding)
   337  		}
   338  
   339  	case "LoanCollateral":
   340  		switch {
   341  		case len(specArgs) <= 0:
   342  			err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> (<innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <controlProgram>) | (<controlProgram>) [flags]\n", usage)
   343  		case specArgs[0] == clauseRepay:
   344  			if len(specArgs) != 6 {
   345  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <controlProgram> [flags]\n", usage)
   346  				return
   347  			}
   348  
   349  			inner := &innerContractArg{
   350  				innerAccountInfo: specArgs[1],
   351  				innerAssetInfo:   specArgs[2],
   352  				innerAmount:      specArgs[3],
   353  				innerProgram:     specArgs[4],
   354  			}
   355  			controlProgram := specArgs[5]
   356  			buildReqStr, err = addLoanCollateralArg(baseArg, specArgs[0], inner, controlProgram)
   357  
   358  		case specArgs[0] == clauseDefault:
   359  			if len(specArgs) != 2 {
   360  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <controlProgram> [flags]\n", usage)
   361  				return
   362  			}
   363  
   364  			controlProgram := specArgs[1]
   365  			buildReqStr, err = addLoanCollateralArg(baseArg, specArgs[0], nil, controlProgram)
   366  
   367  		case specArgs[0] == loanCollateralEnding:
   368  			err = errors.WithDetailf(errBadContractArguments, "Clause ending was selected in contract %s, ending exit\n", contractName)
   369  		default:
   370  			err = errors.WithDetailf(errBadContractArguments, "selected clause [%s] error, contract %s's clause must in set:[%s, %s, %s]\n",
   371  				specArgs[0], contractName, clauseRepay, clauseDefault, loanCollateralEnding)
   372  		}
   373  
   374  	case "CallOption":
   375  		switch {
   376  		case len(specArgs) <= 0:
   377  			err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> (<innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <rootPub> <path1> <path2>) | (<controlProgram>) [flags]\n", usage)
   378  		case specArgs[0] == clauseExercise:
   379  			if len(specArgs) != 8 {
   380  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <rootPub> <path1> <path2> [flags]\n", usage)
   381  				return
   382  			}
   383  
   384  			inner := &innerContractArg{
   385  				innerAccountInfo: specArgs[1],
   386  				innerAssetInfo:   specArgs[2],
   387  				innerAmount:      specArgs[3],
   388  				innerProgram:     specArgs[4],
   389  			}
   390  
   391  			pubInfo := &basePubInfo{
   392  				rootPub: specArgs[5],
   393  				path1:   specArgs[6],
   394  				path2:   specArgs[7],
   395  			}
   396  			buildReqStr, err = addCallOptionArg(baseArg, specArgs[0], inner, pubInfo, "")
   397  
   398  		case specArgs[0] == clauseExpire:
   399  			if len(specArgs) != 2 {
   400  				err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <controlProgram> [flags]\n", usage)
   401  				return
   402  			}
   403  
   404  			controlProgram := specArgs[1]
   405  			buildReqStr, err = addCallOptionArg(baseArg, specArgs[0], nil, nil, controlProgram)
   406  
   407  		case specArgs[0] == callOptionEnding:
   408  			err = errors.WithDetailf(errBadContractArguments, "Clause ending was selected in contract %s, ending exit\n", contractName)
   409  		default:
   410  			err = errors.WithDetailf(errBadContractArguments, "selected clause [%s] error, contract %s's clause must in set:[%s, %s, %s]\n",
   411  				specArgs[0], contractName, clauseExercise, clauseExpire, callOptionEnding)
   412  		}
   413  
   414  	default:
   415  		err = errors.WithDetailf(errBadContractArguments, "Invalid contract template name [%s]", contractName)
   416  	}
   417  
   418  	return
   419  }
   420  
   421  func addLockWithPublicKeyArg(baseArg baseContractArg, pubInfo basePubInfo) (buildReqStr string) {
   422  	buildReqFmt := buildLockWithPublicKeyReqFmt
   423  	if baseArg.alias {
   424  		buildReqFmt = buildLockWithPublicKeyReqFmtByAlias
   425  	}
   426  
   427  	buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
   428  		baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
   429  
   430  	return
   431  }
   432  
   433  func addLockWithMultiSigArg(baseArg baseContractArg, pubInfos [2]basePubInfo) (buildReqStr string) {
   434  	buildReqFmt := buildLockWithMultiSigReqFmt
   435  	if baseArg.alias {
   436  		buildReqFmt = buildLockWithMultiSigReqFmtByAlias
   437  	}
   438  
   439  	buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfos[0].rootPub, pubInfos[0].path1, pubInfos[0].path2,
   440  		pubInfos[1].rootPub, pubInfos[1].path1, pubInfos[1].path2,
   441  		baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
   442  
   443  	return
   444  }
   445  
   446  func addLockWithPublicKeyHashArg(baseArg baseContractArg, pubInfo basePubInfo, pubkey string) (buildReqStr string) {
   447  	buildReqFmt := buildLockWithPublicKeyHashReqFmt
   448  	if baseArg.alias {
   449  		buildReqFmt = buildLockWithPublicKeyHashReqFmtByAlias
   450  	}
   451  
   452  	buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubkey, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
   453  		baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
   454  
   455  	return
   456  }
   457  
   458  func addRevealPreimageArg(baseArg baseContractArg, value string) (buildReqStr string) {
   459  	buildReqFmt := buildCommonRecvReqFmt
   460  	if baseArg.alias {
   461  		buildReqFmt = buildCommonRecvReqFmtByAlias
   462  	}
   463  
   464  	buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, value,
   465  		baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
   466  
   467  	return
   468  }
   469  
   470  func addTradeOfferArg(baseArg baseContractArg, selector string, innerArg *innerContractArg, pubInfo *basePubInfo) (buildReqStr string, err error) {
   471  	switch selector {
   472  	case clauseTrade:
   473  		if innerArg == nil {
   474  			err = errors.New("Contract TradeOffer's clause trade argument is nil")
   475  			return
   476  		}
   477  
   478  		buildReqFmt := buildTradeOfferClauseTradeReqFmt
   479  		if baseArg.alias {
   480  			buildReqFmt = buildTradeOfferClauseTradeReqFmtByAlias
   481  		}
   482  
   483  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
   484  			innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
   485  			innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
   486  			baseArg.btmGas, baseArg.accountInfo,
   487  			baseArg.assetInfo, baseArg.amount, baseArg.program)
   488  
   489  	case clauseCancel:
   490  		if pubInfo == nil {
   491  			err = errors.New("Contract TradeOffer's clause cancel argument is nil")
   492  			return
   493  		}
   494  
   495  		buildReqFmt := buildTradeOfferClauseCancelReqFmt
   496  		if baseArg.alias {
   497  			buildReqFmt = buildTradeOfferClauseCancelReqFmtByAlias
   498  		}
   499  
   500  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
   501  			baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
   502  
   503  	default:
   504  		err = errors.New("Invalid contract clause selector")
   505  	}
   506  
   507  	return
   508  }
   509  
   510  func addEscrowArg(baseArg baseContractArg, selector string, pubInfo *basePubInfo, controlProgram string) (buildReqStr string, err error) {
   511  	switch selector {
   512  	case clauseApprove, clauseReject:
   513  		if pubInfo == nil {
   514  			err = errors.New("Contract Escrow's clause argument is nil")
   515  			return
   516  		}
   517  
   518  		buildReqFmt := buildEscrowReqFmt
   519  		if baseArg.alias {
   520  			buildReqFmt = buildEscrowReqFmtByAlias
   521  		}
   522  
   523  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
   524  			baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
   525  
   526  	default:
   527  		err = errors.New("Invalid contract clause selector")
   528  	}
   529  
   530  	return
   531  }
   532  
   533  func addLoanCollateralArg(baseArg baseContractArg, selector string, innerArg *innerContractArg, controlProgram string) (buildReqStr string, err error) {
   534  	switch selector {
   535  	case clauseRepay:
   536  		if innerArg == nil {
   537  			err = errors.New("Contract LoanCollateral's clause repay argument is nil")
   538  			return
   539  		}
   540  
   541  		buildReqFmt := buildLoanCollateralClauseRepayReqFmt
   542  		if baseArg.alias {
   543  			buildReqFmt = buildLoanCollateralClauseRepayReqFmtByAlias
   544  		}
   545  
   546  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
   547  			innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
   548  			baseArg.assetInfo, baseArg.amount, controlProgram,
   549  			innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
   550  			baseArg.btmGas, baseArg.accountInfo)
   551  
   552  	case clauseDefault:
   553  		buildReqFmt := buildCommonRecvReqFmt
   554  		if baseArg.alias {
   555  			buildReqFmt = buildCommonRecvReqFmtByAlias
   556  		}
   557  
   558  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
   559  			baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
   560  
   561  	default:
   562  		err = errors.New("Invalid contract clause selector")
   563  	}
   564  
   565  	return
   566  }
   567  
   568  func addCallOptionArg(baseArg baseContractArg, selector string, innerArg *innerContractArg, pubInfo *basePubInfo, controlProgram string) (buildReqStr string, err error) {
   569  	switch selector {
   570  	case clauseExercise:
   571  		if innerArg == nil || pubInfo == nil {
   572  			err = errors.New("Contract CallOption's clause exercise argument is nil")
   573  			return
   574  		}
   575  
   576  		buildReqFmt := buildCallOptionClauseExerciseReqFmt
   577  		if baseArg.alias {
   578  			buildReqFmt = buildCallOptionClauseExerciseReqFmtByAlias
   579  		}
   580  
   581  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
   582  			innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
   583  			innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
   584  			baseArg.btmGas, baseArg.accountInfo,
   585  			baseArg.assetInfo, baseArg.amount, baseArg.program)
   586  
   587  	case clauseExpire:
   588  		buildReqFmt := buildCommonRecvReqFmt
   589  		if baseArg.alias {
   590  			buildReqFmt = buildCommonRecvReqFmtByAlias
   591  		}
   592  
   593  		buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
   594  			baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
   595  
   596  	default:
   597  		err = errors.New("Invalid contract clause selector")
   598  	}
   599  
   600  	return
   601  }