9 "github.com/bytom/crypto/ed25519/chainkd"
13 errXPrvLength = errors.New("XPrv length is invalid.")
17 fee = uint64(40000000)
18 confirmations = uint64(1)
21 type TxOutput struct {
22 UTXOID string `json:"utxo_id"`
23 Script string `json:"script"`
24 Address string `json:"address"`
25 AssetID string `json:"asset"`
26 AssetAmount uint64 `json:"amount"`
29 type getTxReq struct {
30 TxID string `json:"tx_id"`
33 type getTxResp struct {
34 TxOutputs []TxOutput `json:"outputs"`
37 // getUTXOID get UTXO ID by transaction ID.
38 func getUTXOID(s *Server, txID, controlProgram string) (string, error) {
39 payload, err := json.Marshal(getTxReq{TxID: txID})
45 if err := s.request(getTransactionURL, payload, res); err != nil {
49 for _, v := range res.TxOutputs {
50 if v.Script == controlProgram {
55 return "", errFailedGetContractUTXOID
58 type SigningInstruction struct {
59 DerivationPath []string `json:"derivation_path"`
60 SignData []string `json:"sign_data"`
61 DataWitness []byte `json:"-"`
63 // only shown for a single-signature tx
64 Pubkey string `json:"pubkey,omitempty"`
67 type SpendUTXOInput struct {
68 Type string `json:"type"`
69 OutputID string `json:"output_id"`
72 type SpendWalletInput struct {
73 Type string `json:"type"`
74 AssetID string `json:"asset"`
75 Amount uint64 `json:"amount"`
78 type ControlAddressOutput struct {
79 Type string `json:"type"`
80 Amount uint64 `json:"amount"`
81 AssetID string `json:"asset"`
82 Address string `json:"address"`
85 type ControlProgramOutput struct {
86 Type string `json:"type"`
87 Amount uint64 `json:"amount"`
88 AssetID string `json:"asset"`
89 ControlProgram string `json:"control_program"`
92 type buildTxReq struct {
93 GUID string `json:"guid"`
94 Fee uint64 `json:"fee"`
95 Confirmations uint64 `json:"confirmations"`
96 Inputs []interface{} `json:"inputs"`
97 Outputs []interface{} `json:"outputs"`
100 type buildTxResp struct {
101 RawTx string `json:"raw_transaction"`
102 SigningInstructions []*SigningInstruction `json:"signing_instructions"`
103 Fee uint64 `json:"fee"`
107 func BuildTx(s *Server, guid, outputID, lockedAsset, contractProgram string, lockedAmount uint64) (string, error) {
109 spendUTXOInput := SpendUTXOInput{
113 spendWalletInput := SpendWalletInput{
114 Type: "spend_wallet",
120 controlProgramOutput := ControlProgramOutput{
121 Type: "control_program",
122 Amount: lockedAmount,
123 AssetID: lockedAsset,
124 ControlProgram: contractProgram,
127 var inputs, outputs []interface{}
128 inputs = append(inputs, spendUTXOInput, spendWalletInput)
129 outputs = append(outputs, controlProgramOutput)
130 payload, err := json.Marshal(buildTxReq{
133 Confirmations: confirmations,
141 fmt.Println("buildTx:", string(payload))
143 res := new(buildTxResp)
144 if err := s.request(buildTransactionURL, payload, res); err != nil {
148 r, err := json.MarshalIndent(res, "", "\t")
153 return string(r), nil
156 type submitPaymentReq struct {
157 GUID string `json:"guid"`
158 RawTx string `json:"raw_transaction"`
159 Signatures [][]string `json:"signatures"`
160 Memo string `json:"memo"`
163 type submitPaymentResp struct {
164 TxID string `json:"transaction_hash"`
167 // submitPayment submit raw transaction and return transaction ID.
168 func submitPayment(s *Server, guid, rawTx, memo string, sigs [][]string) (string, error) {
169 payload, err := json.Marshal(submitPaymentReq{
179 fmt.Println("submitPayment:", string(payload))
181 res := new(submitPaymentResp)
182 if err := s.request(submitTransactionURL, payload, res); err != nil {
189 // SignMsg sign message, return sig.
190 func SignMsg(signData, xprv string) (string, error) {
191 xprvBytes, err := hex.DecodeString(xprv)
195 if len(xprvBytes) != 64 {
196 return "", errXPrvLength
199 var newXPrv chainkd.XPrv
200 copy(newXPrv[:], xprvBytes[:])
202 msg, err := hex.DecodeString(signData)
206 sig := newXPrv.Sign(msg)
207 return hex.EncodeToString(sig), nil
210 // buildUnlockedTx build unlocked contract tx.
211 func buildUnlockedTx(s *Server, guid, contractUTXOID, contractAsset, receiver string, spendWalletAmount, contractAmount uint64) (string, error) {
213 spendUTXOInput := SpendUTXOInput{
215 OutputID: contractUTXOID,
218 spendWalletInput := SpendWalletInput{
219 Type: "spend_wallet",
221 Amount: spendWalletAmount,
225 controlAddressOutput := ControlAddressOutput{
226 Type: "control_address",
227 Amount: contractAmount,
228 AssetID: contractAsset,
232 var inputs, outputs []interface{}
233 inputs = append(inputs, spendUTXOInput, spendWalletInput)
234 outputs = append(outputs, controlAddressOutput)
235 payload, err := json.Marshal(buildTxReq{
238 Confirmations: confirmations,
246 fmt.Println("build unlocked contract tx:", string(payload))
248 res := new(buildTxResp)
249 if err := s.request(buildTransactionURL, payload, res); err != nil {
253 r, err := json.MarshalIndent(res, "", "\t")
258 return string(r), nil
261 // submitUnlockedPayment submit raw transaction and return transaction ID.
262 func submitUnlockedPayment(s *Server, guid, rawTx, memo, spendWalletSig string, spendUTXOSignatures []string) (string, error) {
263 // spendUTXOSignatures := append([]string{}, preimage, spendUTXOSig, "")
264 spendWalletSignatures := append([]string{}, spendWalletSig)
265 sigs := append([][]string{}, spendUTXOSignatures, spendWalletSignatures)
267 payload, err := json.Marshal(submitPaymentReq{
277 fmt.Println("submitUnlockedPayment:", string(payload))
279 res := new(submitPaymentResp)
280 if err := s.request(submitTransactionURL, payload, res); err != nil {
287 // buildCallTradeoffTx build unlocked tradeoff contract tx.
288 func buildCallTradeoffTx(s *Server, guid, contractUTXOID, seller, assetRequested string, spendWalletAmount, contractAmount, amountRequested uint64) (*buildTxResp, error) {
290 spendUTXOInput := SpendUTXOInput{
292 OutputID: contractUTXOID,
295 spendWalletInput := SpendWalletInput{
296 Type: "spend_wallet",
298 Amount: spendWalletAmount,
301 spendWalletUnlockTradeoffInput := SpendWalletInput{
302 Type: "spend_wallet",
303 AssetID: assetRequested,
304 Amount: amountRequested,
308 controlProgramOutput := ControlProgramOutput{
309 Type: "control_program",
310 Amount: amountRequested,
311 AssetID: assetRequested,
312 ControlProgram: seller,
315 var inputs, outputs []interface{}
316 inputs = append(inputs, spendUTXOInput, spendWalletInput, spendWalletUnlockTradeoffInput)
317 outputs = append(outputs, controlProgramOutput)
318 payload, err := json.Marshal(buildTxReq{
321 Confirmations: confirmations,
329 fmt.Println("build unlocked contract tx:", string(payload))
331 res := new(buildTxResp)
332 if err := s.request(buildTransactionURL, payload, res); err != nil {