OSDN Git Service

add contract template LoanCollateral (#1125)
authoroysheng <33340252+oysheng@users.noreply.github.com>
Fri, 6 Jul 2018 08:07:30 +0000 (16:07 +0800)
committerPaladz <yzhu101@uottawa.ca>
Fri, 6 Jul 2018 08:07:30 +0000 (16:07 +0800)
add contract template CallOption

cmd/bytomcli/commands/template.go

index 384e9e4..bf62f17 100644 (file)
@@ -14,14 +14,40 @@ const (
 
        // contract Escrow's clause
        clauseApprove = "00000000"
-       clauseReject  = "1b000000"
-       escrowEnding  = "2a000000"
+       clauseReject  = "1a000000"
+       escrowEnding  = "28000000"
+
+       // contract LoanCollateral's clause
+       clauseRepay          = "00000000"
+       clauseDefault        = "1b000000"
+       loanCollateralEnding = "26000000"
+
+       // contract CallOption's clause
+       clauseExercise   string = "00000000"
+       clauseExpire     string = "20000000"
+       callOptionEnding string = "2c000000"
 )
 
 var (
        errBadContractArguments = errors.New("bad contract arguments")
 )
 
+// common receiver template, the clause takes only one parameter without Signature in the contract that contains only one clause,
+// 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"
+var buildCommonRecvReqFmt = `
+       {"actions": [
+               {"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
+               {"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
+       ]}`
+
+var buildCommonRecvReqFmtByAlias = `
+       {"actions": [
+               {"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
+               {"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
+       ]}`
+
 // contract is LockWithPublicKey
 var buildLockWithPublicKeyReqFmt = `
        {"actions": [
@@ -71,21 +97,6 @@ var buildLockWithPublicKeyHashReqFmtByAlias = `
                {"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
        ]}`
 
-// contract is RevealPreimage
-var buildRevealPreimageReqFmt = `
-       {"actions": [
-               {"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
-               {"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
-               {"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"}
-       ]}`
-
-var buildRevealPreimageReqFmtByAlias = `
-       {"actions": [
-               {"type": "spend_account_unspent_output", "output_id": "%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
-               {"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
-               {"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
-       ]}`
-
 // contract is TradeOffer's clause trade, the code of clause contains only two statement with "lock payment with program" and "unlock value"
 var buildTradeOfferClauseTradeReqFmt = `
        {"actions": [
@@ -139,6 +150,46 @@ var buildEscrowReqFmtByAlias = `
                {"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
        ]}`
 
+// 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"
+var buildLoanCollateralClauseRepayReqFmt = `
+       {"actions": [
+               {"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
+               {"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "spend_account", "asset_id": "%s", "amount": %s, "account_id": "%s"},
+               {"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount":%s, "account_id": "%s"}
+       ]}`
+
+var buildLoanCollateralClauseRepayReqFmtByAlias = `
+       {"actions": [
+               {"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "data", "raw_data": {"value": "%s"}}]},
+               {"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "spend_account", "asset_alias": "%s", "amount": %s, "account_alias": "%s"},
+               {"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"}
+       ]}`
+
+// contract is CallOption's clause exercise, the code of clause contains only two statement with "lock payment with program" and "unlock value"
+var buildCallOptionClauseExerciseReqFmt = `
+       {"actions": [
+               {"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
+                               {"type": "data", "raw_data": {"value": "%s"}}]},
+               {"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "spend_account", "asset_id": "%s", "amount": %s, "account_id": "%s"},
+               {"type": "spend_account", "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount":%s, "account_id": "%s"},
+               {"type": "control_program", "asset_id": "%s", "amount": %s, "control_program": "%s"}
+       ]}`
+
+var buildCallOptionClauseExerciseReqFmtByAlias = `
+       {"actions": [
+               {"type": "spend_account_unspent_output", "output_id":"%s", "arguments": [{"type": "raw_tx_signature", "raw_data": {"xpub": "%s", "derivation_path": ["%s", "%s"]}},
+                               {"type": "data", "raw_data": {"value": "%s"}}]},
+               {"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"},
+               {"type": "spend_account", "asset_alias": "%s", "amount": %s, "account_alias": "%s"},
+               {"type": "spend_account", "asset_alias": "BTM", "amount": %s, "account_alias": "%s"},
+               {"type": "control_program", "asset_alias": "%s", "amount": %s, "control_program": "%s"}
+       ]}`
+
 // contract arguments
 type baseContractArg struct {
        accountInfo string
@@ -285,6 +336,81 @@ func addContractArgs(contractName string, baseArg baseContractArg, specArgs []st
                                specArgs[0], contractName, clauseApprove, clauseReject, escrowEnding)
                }
 
+       case "LoanCollateral":
+               switch {
+               case len(specArgs) <= 0:
+                       err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> (<innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <controlProgram>) | (<controlProgram>) [flags]\n", usage)
+               case specArgs[0] == clauseRepay:
+                       if len(specArgs) != 6 {
+                               err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <controlProgram> [flags]\n", usage)
+                               return
+                       }
+
+                       inner := &innerContractArg{
+                               innerAccountInfo: specArgs[1],
+                               innerAssetInfo:   specArgs[2],
+                               innerAmount:      specArgs[3],
+                               innerProgram:     specArgs[4],
+                       }
+                       controlProgram := specArgs[5]
+                       buildReqStr, err = addLoanCollateralArg(baseArg, specArgs[0], inner, controlProgram)
+
+               case specArgs[0] == clauseDefault:
+                       if len(specArgs) != 2 {
+                               err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <controlProgram> [flags]\n", usage)
+                               return
+                       }
+
+                       controlProgram := specArgs[1]
+                       buildReqStr, err = addLoanCollateralArg(baseArg, specArgs[0], nil, controlProgram)
+
+               case specArgs[0] == loanCollateralEnding:
+                       err = errors.WithDetailf(errBadContractArguments, "Clause ending was selected in contract %s, ending exit\n", contractName)
+               default:
+                       err = errors.WithDetailf(errBadContractArguments, "selected clause [%s] error, contract %s's clause must in set:[%s, %s, %s]\n",
+                               specArgs[0], contractName, clauseRepay, clauseDefault, loanCollateralEnding)
+               }
+
+       case "CallOption":
+               switch {
+               case len(specArgs) <= 0:
+                       err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> (<innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <rootPub> <path1> <path2>) | (<controlProgram>) [flags]\n", usage)
+               case specArgs[0] == clauseExercise:
+                       if len(specArgs) != 8 {
+                               err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <innerAccountID|alias> <innerAssetID|alias> <innerAmount> <innerProgram> <rootPub> <path1> <path2> [flags]\n", usage)
+                               return
+                       }
+
+                       inner := &innerContractArg{
+                               innerAccountInfo: specArgs[1],
+                               innerAssetInfo:   specArgs[2],
+                               innerAmount:      specArgs[3],
+                               innerProgram:     specArgs[4],
+                       }
+
+                       pubInfo := &basePubInfo{
+                               rootPub: specArgs[5],
+                               path1:   specArgs[6],
+                               path2:   specArgs[7],
+                       }
+                       buildReqStr, err = addCallOptionArg(baseArg, specArgs[0], inner, pubInfo, "")
+
+               case specArgs[0] == clauseExpire:
+                       if len(specArgs) != 2 {
+                               err = errors.WithDetailf(errBadContractArguments, "%s <clauseSelector> <controlProgram> [flags]\n", usage)
+                               return
+                       }
+
+                       controlProgram := specArgs[1]
+                       buildReqStr, err = addCallOptionArg(baseArg, specArgs[0], nil, nil, controlProgram)
+
+               case specArgs[0] == callOptionEnding:
+                       err = errors.WithDetailf(errBadContractArguments, "Clause ending was selected in contract %s, ending exit\n", contractName)
+               default:
+                       err = errors.WithDetailf(errBadContractArguments, "selected clause [%s] error, contract %s's clause must in set:[%s, %s, %s]\n",
+                               specArgs[0], contractName, clauseExercise, clauseExpire, callOptionEnding)
+               }
+
        default:
                err = errors.WithDetailf(errBadContractArguments, "Invalid contract template name [%s]", contractName)
        }
@@ -293,48 +419,51 @@ func addContractArgs(contractName string, baseArg baseContractArg, specArgs []st
 }
 
 func addLockWithPublicKeyArg(baseArg baseContractArg, pubInfo basePubInfo) (buildReqStr string) {
-       buildReqStr = fmt.Sprintf(buildLockWithPublicKeyReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
-               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+       buildReqFmt := buildLockWithPublicKeyReqFmt
        if baseArg.alias {
-               buildReqStr = fmt.Sprintf(buildLockWithPublicKeyReqFmtByAlias, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
-                       baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+               buildReqFmt = buildLockWithPublicKeyReqFmtByAlias
        }
 
+       buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
+               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+
        return
 }
 
 func addLockWithMultiSigArg(baseArg baseContractArg, pubInfos [2]basePubInfo) (buildReqStr string) {
-       buildReqStr = fmt.Sprintf(buildLockWithMultiSigReqFmt, baseArg.outputID, pubInfos[0].rootPub, pubInfos[0].path1, pubInfos[0].path2,
-               pubInfos[1].rootPub, pubInfos[1].path1, pubInfos[1].path2,
-               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+       buildReqFmt := buildLockWithMultiSigReqFmt
        if baseArg.alias {
-               buildReqStr = fmt.Sprintf(buildLockWithMultiSigReqFmtByAlias, baseArg.outputID, pubInfos[0].rootPub, pubInfos[0].path1, pubInfos[0].path2,
-                       pubInfos[1].rootPub, pubInfos[1].path1, pubInfos[1].path2,
-                       baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+               buildReqFmt = buildLockWithMultiSigReqFmtByAlias
        }
 
+       buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfos[0].rootPub, pubInfos[0].path1, pubInfos[0].path2,
+               pubInfos[1].rootPub, pubInfos[1].path1, pubInfos[1].path2,
+               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+
        return
 }
 
 func addLockWithPublicKeyHashArg(baseArg baseContractArg, pubInfo basePubInfo, pubkey string) (buildReqStr string) {
-       buildReqStr = fmt.Sprintf(buildLockWithPublicKeyHashReqFmt, baseArg.outputID, pubkey, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
-               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
-       if alias {
-               buildReqStr = fmt.Sprintf(buildLockWithPublicKeyHashReqFmtByAlias, baseArg.outputID, pubkey, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
-                       baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+       buildReqFmt := buildLockWithPublicKeyHashReqFmt
+       if baseArg.alias {
+               buildReqFmt = buildLockWithPublicKeyHashReqFmtByAlias
        }
 
+       buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubkey, pubInfo.rootPub, pubInfo.path1, pubInfo.path2,
+               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+
        return
 }
 
 func addRevealPreimageArg(baseArg baseContractArg, value string) (buildReqStr string) {
-       buildReqStr = fmt.Sprintf(buildRevealPreimageReqFmt, baseArg.outputID, value,
-               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+       buildReqFmt := buildCommonRecvReqFmt
        if baseArg.alias {
-               buildReqStr = fmt.Sprintf(buildRevealPreimageReqFmtByAlias, baseArg.outputID, value,
-                       baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+               buildReqFmt = buildCommonRecvReqFmtByAlias
        }
 
+       buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, value,
+               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+
        return
 }
 
@@ -346,18 +475,16 @@ func addTradeOfferArg(baseArg baseContractArg, selector string, innerArg *innerC
                        return
                }
 
-               buildReqStr = fmt.Sprintf(buildTradeOfferClauseTradeReqFmt, baseArg.outputID, clauseTrade,
+               buildReqFmt := buildTradeOfferClauseTradeReqFmt
+               if baseArg.alias {
+                       buildReqFmt = buildTradeOfferClauseTradeReqFmtByAlias
+               }
+
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
                        innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
                        innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
                        baseArg.btmGas, baseArg.accountInfo,
                        baseArg.assetInfo, baseArg.amount, baseArg.program)
-               if baseArg.alias {
-                       buildReqStr = fmt.Sprintf(buildTradeOfferClauseTradeReqFmtByAlias, baseArg.outputID, clauseTrade,
-                               innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
-                               innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
-                               baseArg.btmGas, baseArg.accountInfo,
-                               baseArg.assetInfo, baseArg.amount, baseArg.program)
-               }
 
        case clauseCancel:
                if pubInfo == nil {
@@ -365,13 +492,14 @@ func addTradeOfferArg(baseArg baseContractArg, selector string, innerArg *innerC
                        return
                }
 
-               buildReqStr = fmt.Sprintf(buildTradeOfferClauseCancelReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, clauseCancel,
-                       baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+               buildReqFmt := buildTradeOfferClauseCancelReqFmt
                if baseArg.alias {
-                       buildReqStr = fmt.Sprintf(buildTradeOfferClauseCancelReqFmtByAlias, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, clauseCancel,
-                               baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+                       buildReqFmt = buildTradeOfferClauseCancelReqFmtByAlias
                }
 
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
+                       baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo)
+
        default:
                err = errors.New("Invalid contract clause selector")
        }
@@ -387,13 +515,84 @@ func addEscrowArg(baseArg baseContractArg, selector string, pubInfo *basePubInfo
                        return
                }
 
-               buildReqStr = fmt.Sprintf(buildEscrowReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
+               buildReqFmt := buildEscrowReqFmt
+               if baseArg.alias {
+                       buildReqFmt = buildEscrowReqFmtByAlias
+               }
+
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
+                       baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
+
+       default:
+               err = errors.New("Invalid contract clause selector")
+       }
+
+       return
+}
+
+func addLoanCollateralArg(baseArg baseContractArg, selector string, innerArg *innerContractArg, controlProgram string) (buildReqStr string, err error) {
+       switch selector {
+       case clauseRepay:
+               if innerArg == nil {
+                       err = errors.New("Contract LoanCollateral's clause repay argument is nil")
+                       return
+               }
+
+               buildReqFmt := buildLoanCollateralClauseRepayReqFmt
+               if baseArg.alias {
+                       buildReqFmt = buildLoanCollateralClauseRepayReqFmtByAlias
+               }
+
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
+                       innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
+                       baseArg.assetInfo, baseArg.amount, controlProgram,
+                       innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
+                       baseArg.btmGas, baseArg.accountInfo)
+
+       case clauseDefault:
+               buildReqFmt := buildCommonRecvReqFmt
+               if baseArg.alias {
+                       buildReqFmt = buildCommonRecvReqFmtByAlias
+               }
+
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
                        baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
+
+       default:
+               err = errors.New("Invalid contract clause selector")
+       }
+
+       return
+}
+
+func addCallOptionArg(baseArg baseContractArg, selector string, innerArg *innerContractArg, pubInfo *basePubInfo, controlProgram string) (buildReqStr string, err error) {
+       switch selector {
+       case clauseExercise:
+               if innerArg == nil || pubInfo == nil {
+                       err = errors.New("Contract CallOption's clause exercise argument is nil")
+                       return
+               }
+
+               buildReqFmt := buildCallOptionClauseExerciseReqFmt
                if baseArg.alias {
-                       buildReqStr = fmt.Sprintf(buildEscrowReqFmtByAlias, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
-                               baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
+                       buildReqFmt = buildCallOptionClauseExerciseReqFmtByAlias
                }
 
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, selector,
+                       innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerProgram,
+                       innerArg.innerAssetInfo, innerArg.innerAmount, innerArg.innerAccountInfo,
+                       baseArg.btmGas, baseArg.accountInfo,
+                       baseArg.assetInfo, baseArg.amount, baseArg.program)
+
+       case clauseExpire:
+               buildReqFmt := buildCommonRecvReqFmt
+               if baseArg.alias {
+                       buildReqFmt = buildCommonRecvReqFmtByAlias
+               }
+
+               buildReqStr = fmt.Sprintf(buildReqFmt, baseArg.outputID, selector,
+                       baseArg.assetInfo, baseArg.amount, controlProgram, baseArg.btmGas, baseArg.accountInfo)
+
        default:
                err = errors.New("Invalid contract clause selector")
        }