From: oysheng <33340252+oysheng@users.noreply.github.com> Date: Tue, 3 Jul 2018 06:14:12 +0000 (+0800) Subject: add contract TradeOffer template (#1116) X-Git-Tag: v1.0.5~7^2~27 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=c291c634e6d7b07a0408c4d9ed79f679884a6d62;p=bytom%2Fbytom.git add contract TradeOffer template (#1116) * add contract TradeOffer template * refactor template contract * fix error result --- diff --git a/cmd/bytomcli/commands/template.go b/cmd/bytomcli/commands/template.go index b48f4f41..9c5dde0b 100644 --- a/cmd/bytomcli/commands/template.go +++ b/cmd/bytomcli/commands/template.go @@ -1,5 +1,19 @@ package commands +import ( + "fmt" + + "github.com/bytom/errors" +) + +var ( + clauseTrade = "00000000" + clauseCancel = "13000000" + tradeOfferEnding = "1a000000" + + errBadContractArguments = errors.New("bad contract arguments") +) + // contract is LockWithPublicKey var buildLockWithPublicKeyReqFmt = ` {"actions": [ @@ -63,3 +77,253 @@ var buildRevealPreimageReqFmtByAlias = ` {"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": [ + {"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": "%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 buildTradeOfferClauseTradeReqFmtByAlias = ` + {"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": "%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 is TradeOffer's clause cancel +var buildTradeOfferClauseCancelReqFmt = ` + {"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": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "amount": %s, "account_id": "%s"} + ]}` + +var buildTradeOfferClauseCancelReqFmtByAlias = ` + {"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": "BTM", "amount": %s, "account_alias": "%s"} + ]}` + +// contract arguments +type baseContractArg struct { + accountInfo string + assetInfo string + amount string + alias bool + program string + btmGas string + outputID string +} + +type basePubInfo struct { + rootPub string + path1 string + path2 string +} + +type innerContractArg struct { + innerAccountInfo string + innerAssetInfo string + innerAmount string + innerProgram string +} + +// addContractArgs add arguments for template contracts +func addContractArgs(contractName string, baseArg baseContractArg, specArgs []string, usage string) (buildReqStr string, err error) { + switch contractName { + case "LockWithPublicKey": + if len(specArgs) != 3 { + err = errors.WithDetailf(errBadContractArguments, "%s [flags]\n", usage) + return + } + + pubInfo := basePubInfo{ + rootPub: specArgs[0], + path1: specArgs[1], + path2: specArgs[2], + } + buildReqStr = addLockWithPublicKeyArg(baseArg, pubInfo) + + case "LockWithMultiSig": + if len(specArgs) != 6 { + err = errors.WithDetailf(errBadContractArguments, "%s [flags]\n", usage) + return + } + + pubInfos := [2]basePubInfo{ + { + rootPub: specArgs[0], + path1: specArgs[1], + path2: specArgs[2], + }, + { + rootPub: specArgs[3], + path1: specArgs[4], + path2: specArgs[5], + }, + } + buildReqStr = addLockWithMultiSigArg(baseArg, pubInfos) + + case "LockWithPublicKeyHash": + if len(specArgs) != 4 { + err = errors.WithDetailf(errBadContractArguments, "%s [flags]\n", usage) + return + } + + pubkey := specArgs[0] + pubInfo := basePubInfo{ + rootPub: specArgs[1], + path1: specArgs[2], + path2: specArgs[3], + } + buildReqStr = addLockWithPublicKeyHashArg(baseArg, pubInfo, pubkey) + + case "RevealPreimage": + if len(specArgs) != 1 { + err = errors.WithDetailf(errBadContractArguments, "%s [flags]\n", usage) + return + } + + value := specArgs[0] + buildReqStr = addRevealPreimageArg(baseArg, value) + + case "TradeOffer": + switch { + case len(specArgs) <= 0: + err = errors.WithDetailf(errBadContractArguments, "%s ( ) | ( ) [flags]\n", usage) + case specArgs[0] == clauseTrade: + if len(specArgs) != 5 { + err = errors.WithDetailf(errBadContractArguments, "%s [flags]\n", usage) + return + } + + inner := &innerContractArg{ + innerAccountInfo: specArgs[1], + innerAssetInfo: specArgs[2], + innerAmount: specArgs[3], + innerProgram: specArgs[4], + } + buildReqStr, err = addTradeOfferArg(baseArg, clauseTrade, inner, nil) + + case specArgs[0] == clauseCancel: + if len(specArgs) != 4 { + err = errors.WithDetailf(errBadContractArguments, "%s [flags]\n", usage) + return + } + + pubInfo := &basePubInfo{ + rootPub: specArgs[1], + path1: specArgs[2], + path2: specArgs[3], + } + buildReqStr, err = addTradeOfferArg(baseArg, clauseCancel, nil, pubInfo) + + case specArgs[0] == tradeOfferEnding: + 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, clauseTrade, clauseCancel, tradeOfferEnding) + } + default: + err = errors.WithDetailf(errBadContractArguments, "Invalid contract template name [%s]", contractName) + } + + return +} + +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) + 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) + } + + 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) + 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) + } + + 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) + } + + 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) + if baseArg.alias { + buildReqStr = fmt.Sprintf(buildRevealPreimageReqFmtByAlias, baseArg.outputID, value, + baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo) + } + + return +} + +func addTradeOfferArg(baseArg baseContractArg, selector string, innerArg *innerContractArg, pubInfo *basePubInfo) (buildReqStr string, err error) { + switch selector { + case clauseTrade: + if innerArg == nil { + err = errors.New("Contract TradeOffer's clause trade argument is nil") + return + } + + buildReqStr = fmt.Sprintf(buildTradeOfferClauseTradeReqFmt, 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) + 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 { + err = errors.New("Contract TradeOffer's clause cancel argument is nil") + return + } + + buildReqStr = fmt.Sprintf(buildTradeOfferClauseCancelReqFmt, baseArg.outputID, pubInfo.rootPub, pubInfo.path1, pubInfo.path2, clauseCancel, + baseArg.assetInfo, baseArg.amount, baseArg.program, baseArg.btmGas, baseArg.accountInfo) + 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) + } + + default: + err = errors.New("Invalid contract clause selector") + } + + return +} diff --git a/cmd/bytomcli/commands/transaction.go b/cmd/bytomcli/commands/transaction.go index 576170ad..d1b7aad4 100644 --- a/cmd/bytomcli/commands/transaction.go +++ b/cmd/bytomcli/commands/transaction.go @@ -172,77 +172,27 @@ var buildTransactionCmd = &cobra.Command{ } buildReqStr = fmt.Sprintf(buildControlProgramReqFmt, btmGas, accountInfo, assetInfo, amount, accountInfo, assetInfo, amount, program) case "unlock": + var err error usage := "Usage:\n bytomcli build-transaction -c " - if len(args) <= 3 { + baseCount := 4 + if len(args) < baseCount { jww.ERROR.Printf("%s ... [flags]\n\n", usage) os.Exit(util.ErrLocalExe) } - outputID := args[3] - switch contractName { - case "LockWithPublicKey": - if len(args) != 7 { - jww.ERROR.Printf("%s [flags]\n\n", usage) - os.Exit(util.ErrLocalExe) - } - - rootPub := args[4] - path1 := args[5] - path2 := args[6] - if alias { - buildReqStr = fmt.Sprintf(buildLockWithPublicKeyReqFmtByAlias, outputID, rootPub, path1, path2, assetInfo, amount, program, btmGas, accountInfo) - break - } - buildReqStr = fmt.Sprintf(buildLockWithPublicKeyReqFmt, outputID, rootPub, path1, path2, assetInfo, amount, program, btmGas, accountInfo) - - case "LockWithMultiSig": - if len(args) != 10 { - jww.ERROR.Printf("%s [flags]\n\n", usage) - os.Exit(util.ErrLocalExe) - } - - rootPub1 := args[4] - path11 := args[5] - path12 := args[6] - rootPub2 := args[7] - path21 := args[8] - path22 := args[9] - if alias { - buildReqStr = fmt.Sprintf(buildLockWithMultiSigReqFmtByAlias, outputID, rootPub1, path11, path12, rootPub2, path21, path22, assetInfo, amount, program, btmGas, accountInfo) - break - } - buildReqStr = fmt.Sprintf(buildLockWithMultiSigReqFmt, outputID, rootPub1, path11, path12, rootPub2, path21, path22, assetInfo, amount, program, btmGas, accountInfo) - - case "LockWithPublicKeyHash": - if len(args) != 8 { - jww.ERROR.Printf("%s [flags]\n\n", usage) - os.Exit(util.ErrLocalExe) - } - - pubkey := args[4] - rootPub := args[5] - path1 := args[6] - path2 := args[7] - if alias { - buildReqStr = fmt.Sprintf(buildLockWithPublicKeyHashReqFmtByAlias, outputID, pubkey, rootPub, path1, path2, assetInfo, amount, program, btmGas, accountInfo) - break - } - buildReqStr = fmt.Sprintf(buildLockWithPublicKeyHashReqFmt, outputID, pubkey, rootPub, path1, path2, assetInfo, amount, program, btmGas, accountInfo) - - case "RevealPreimage": - if len(args) != 5 { - jww.ERROR.Printf("%s [flags]\n\n", usage) - os.Exit(util.ErrLocalExe) - } - - value := args[4] - if alias { - buildReqStr = fmt.Sprintf(buildRevealPreimageReqFmtByAlias, outputID, value, assetInfo, amount, program, btmGas, accountInfo) - break - } - buildReqStr = fmt.Sprintf(buildRevealPreimageReqFmt, outputID, value, assetInfo, amount, program, btmGas, accountInfo) - - default: - jww.ERROR.Printf("Invalid Contract template: %s\n\n", contractName) + + baseArg := baseContractArg{ + accountInfo: accountInfo, + assetInfo: assetInfo, + amount: amount, + alias: alias, + program: program, + btmGas: btmGas, + outputID: args[baseCount-1], + } + specArgs := args[baseCount:] + + if buildReqStr, err = addContractArgs(contractName, baseArg, specArgs, usage); err != nil { + jww.ERROR.Println(err) os.Exit(util.ErrLocalExe) }