9 "github.com/bytom/crypto/ed25519/chainkd"
13 errXPrvLength = errors.New("XPrv length is invalid.")
14 errFailedGetContractUTXOID = errors.New("Failed to get contract UTXO ID")
17 type TxOutput struct {
18 UTXOID string `json:"utxo_id"`
19 Script string `json:"script"`
22 type getTxReq struct {
23 TxID string `json:"tx_id"`
26 type getTxResp struct {
27 TxOutputs []TxOutput `json:"outputs"`
30 // getUTXOID get UTXO ID by transaction ID.
31 func getUTXOID(s *Server, txID, controlProgram string) (string, error) {
32 payload, err := json.Marshal(getTxReq{TxID: txID})
38 if err := s.request(getTransactionURL, payload, res); err != nil {
42 for _, v := range res.TxOutputs {
43 if v.Script == controlProgram {
48 return "", errFailedGetContractUTXOID
51 type SigningInstruction struct {
52 DerivationPath []string `json:"derivation_path"`
53 SignData []string `json:"sign_data"`
54 DataWitness []byte `json:"-"`
56 // only shown for a single-signature tx
57 Pubkey string `json:"pubkey,omitempty"`
60 type SpendUTXOInput struct {
61 Type string `json:"type"`
62 OutputID string `json:"output_id"`
65 type SpendWalletInput struct {
66 Type string `json:"type"`
67 AssetID string `json:"asset"`
68 Amount uint64 `json:"amount"`
71 type ControlAddressOutput struct {
72 Type string `json:"type"`
73 Amount uint64 `json:"amount"`
74 AssetID string `json:"asset"`
75 Address string `json:"address"`
78 type ControlProgramOutput struct {
79 Type string `json:"type"`
80 Amount uint64 `json:"amount"`
81 AssetID string `json:"asset"`
82 ControlProgram string `json:"control_program"`
85 type buildTxReq struct {
86 GUID string `json:"guid"`
87 Fee uint64 `json:"fee"`
88 Confirmations uint64 `json:"confirmations"`
89 Inputs []interface{} `json:"inputs"`
90 Outputs []interface{} `json:"outputs"`
93 type buildTxResp struct {
94 RawTx string `json:"raw_transaction"`
95 SigningInstructions []*SigningInstruction `json:"signing_instructions"`
96 Fee uint64 `json:"fee"`
100 func BuildTx(s *Server, guid, lockedAsset, contractProgram string, lockedAmount uint64) (string, error) {
102 spendWalletInput := SpendWalletInput{
103 Type: "spend_wallet",
104 AssetID: lockedAsset,
105 Amount: lockedAmount,
109 controlProgramOutput := ControlProgramOutput{
110 Type: "control_program",
111 Amount: lockedAmount,
112 AssetID: lockedAsset,
113 ControlProgram: contractProgram,
116 var inputs, outputs []interface{}
117 inputs = append(inputs, spendWalletInput)
118 outputs = append(outputs, controlProgramOutput)
119 payload, err := json.Marshal(buildTxReq{
122 Confirmations: confirmations,
130 fmt.Println("buildTx:", string(payload))
132 res := new(buildTxResp)
133 if err := s.request(buildTransactionURL, payload, res); err != nil {
137 r, err := json.MarshalIndent(res, "", "\t")
142 return string(r), nil
145 type submitPaymentReq struct {
146 GUID string `json:"guid"`
147 RawTx string `json:"raw_transaction"`
148 Signatures [][]string `json:"signatures"`
149 Memo string `json:"memo"`
152 type submitPaymentResp struct {
153 TxID string `json:"transaction_hash"`
156 // SubmitPayment submit raw transaction and return transaction ID.
157 func SubmitPayment(s *Server, guid, rawTx, memo string, sigs [][]string) (string, error) {
158 payload, err := json.MarshalIndent(submitPaymentReq{
168 fmt.Println("\nsubmitPayment:", string(payload))
170 res := new(submitPaymentResp)
171 if err := s.request(submitTransactionURL, payload, res); err != nil {
178 // SignMessage sign message, return sig.
179 func SignMessage(signData, xprv string) (string, error) {
180 xprvBytes, err := hex.DecodeString(xprv)
184 if len(xprvBytes) != 64 {
185 return "", errXPrvLength
188 var newXPrv chainkd.XPrv
189 copy(newXPrv[:], xprvBytes[:])
191 msg, err := hex.DecodeString(signData)
195 sig := newXPrv.Sign(msg)
196 return hex.EncodeToString(sig), nil
199 // BuildUnlockedTx build unlocked contract tx.
200 func BuildUnlockedTx(s *Server, guid, contractUTXOID, lockedAsset, receiver string, lockedAmount uint64) (string, error) {
202 spendUTXOInput := SpendUTXOInput{
204 OutputID: contractUTXOID,
208 controlAddressOutput := ControlAddressOutput{
209 Type: "control_address",
210 Amount: lockedAmount,
211 AssetID: lockedAsset,
215 var inputs, outputs []interface{}
216 // inputs = append(inputs, spendUTXOInput, spendWalletInput)
217 inputs = append(inputs, spendUTXOInput)
218 outputs = append(outputs, controlAddressOutput)
219 payload, err := json.Marshal(buildTxReq{
222 Confirmations: confirmations,
230 fmt.Println("build unlocked contract tx:", string(payload))
232 res := new(buildTxResp)
233 if err := s.request(buildTransactionURL, payload, res); err != nil {
237 r, err := json.MarshalIndent(res, "", "\t")
242 return string(r), nil
245 // BuildCallTradeoffTx build unlocked tradeoff contract tx.
246 func BuildCallTradeoffTx(s *Server, guid, contractUTXOID, seller, assetRequested string, amountRequested uint64) (string, error) {
248 spendUTXOInput := SpendUTXOInput{
250 OutputID: contractUTXOID,
253 spendWalletUnlockTradeoffInput := SpendWalletInput{
254 Type: "spend_wallet",
255 AssetID: assetRequested,
256 Amount: amountRequested,
260 controlProgramOutput := ControlProgramOutput{
261 Type: "control_program",
262 Amount: amountRequested,
263 AssetID: assetRequested,
264 ControlProgram: seller,
267 var inputs, outputs []interface{}
268 inputs = append(inputs, spendUTXOInput, spendWalletUnlockTradeoffInput)
269 outputs = append(outputs, controlProgramOutput)
270 payload, err := json.Marshal(buildTxReq{
273 Confirmations: confirmations,
281 fmt.Println("build unlocked contract tx:", string(payload))
283 res := new(buildTxResp)
284 if err := s.request(buildTransactionURL, payload, res); err != nil {
288 r, err := json.MarshalIndent(res, "", "\t")
293 return string(r), nil