9 "github.com/bytom/crypto/ed25519/chainkd"
13 errXPrvLength = errors.New("XPrv length is invalid.")
16 type TxOutput struct {
17 UTXOID string `json:"utxo_id"`
18 Script string `json:"script"`
19 Address string `json:"address"`
20 AssetID string `json:"asset"`
21 AssetAmount uint64 `json:"amount"`
24 type getTxReq struct {
25 TxID string `json:"tx_id"`
28 type getTxResp struct {
29 TxOutputs []TxOutput `json:"outputs"`
32 // getUTXOID get UTXO ID by transaction ID.
33 func getUTXOID(s *Server, txID, controlProgram string) (string, error) {
34 payload, err := json.Marshal(getTxReq{TxID: txID})
40 if err := s.request(getTransactionURL, payload, res); err != nil {
44 for _, v := range res.TxOutputs {
45 if v.Script == controlProgram {
50 return "", errFailedGetContractUTXOID
53 type SigningInstruction struct {
54 DerivationPath []string `json:"derivation_path"`
55 SignData []string `json:"sign_data"`
56 DataWitness []byte `json:"-"`
58 // only shown for a single-signature tx
59 Pubkey string `json:"pubkey,omitempty"`
62 type SpendUTXOInput struct {
63 Type string `json:"type"`
64 OutputID string `json:"output_id"`
67 type SpendWalletInput struct {
68 Type string `json:"type"`
69 AssetID string `json:"asset"`
70 Amount uint64 `json:"amount"`
73 type ControlAddressOutput struct {
74 Type string `json:"type"`
75 Amount uint64 `json:"amount"`
76 AssetID string `json:"asset"`
77 Address string `json:"address"`
80 type ControlProgramOutput struct {
81 Type string `json:"type"`
82 Amount uint64 `json:"amount"`
83 AssetID string `json:"asset"`
84 ControlProgram string `json:"control_program"`
87 type buildTxReq struct {
88 GUID string `json:"guid"`
89 Fee uint64 `json:"fee"`
90 Confirmations uint64 `json:"confirmations"`
91 Inputs []interface{} `json:"inputs"`
92 Outputs []interface{} `json:"outputs"`
95 type buildTxResp struct {
96 RawTx string `json:"raw_transaction"`
97 SigningInstructions []*SigningInstruction `json:"signing_instructions"`
98 Fee uint64 `json:"fee"`
102 func buildTx(s *Server, guid, outputID, lockedAsset, contractProgram string, fee, confirmations, lockedAmount uint64) (*buildTxResp, error) {
104 spendUTXOInput := SpendUTXOInput{
108 spendWalletInput := SpendWalletInput{
109 Type: "spend_wallet",
115 controlProgramOutput := ControlProgramOutput{
116 Type: "control_program",
117 Amount: lockedAmount,
118 AssetID: lockedAsset,
119 ControlProgram: contractProgram,
122 var inputs, outputs []interface{}
123 inputs = append(inputs, spendUTXOInput, spendWalletInput)
124 outputs = append(outputs, controlProgramOutput)
125 payload, err := json.Marshal(buildTxReq{
128 Confirmations: confirmations,
136 fmt.Println("buildTx:", string(payload))
138 res := new(buildTxResp)
139 if err := s.request(buildTransactionURL, payload, res); err != nil {
146 type submitPaymentReq struct {
147 GUID string `json:"guid"`
148 RawTx string `json:"raw_transaction"`
149 Signatures [][]string `json:"signatures"`
150 Memo string `json:"memo"`
153 type submitPaymentResp struct {
154 TxID string `json:"transaction_hash"`
157 // submitPayment submit raw transaction and return transaction ID.
158 func submitPayment(s *Server, guid, rawTx, memo, spendWalletSig string, spendUTXOSignatures []string) (string, error) {
159 // spendUTXOSignatures := append([]string{}, spendUTXOSig, spendUTXOPublicKey)
160 spendWalletSignatures := append([]string{}, spendWalletSig)
161 sigs := append([][]string{}, spendUTXOSignatures, spendWalletSignatures)
163 payload, err := json.Marshal(submitPaymentReq{
173 res := new(submitPaymentResp)
174 if err := s.request(submitTransactionURL, payload, res); err != nil {
181 // signMessage sign message, return sig.
182 func signMsg(signData, xprv string) (string, error) {
183 xprvBytes, err := hex.DecodeString(xprv)
187 if len(xprvBytes) != 64 {
188 return "", errXPrvLength
191 var newXPrv chainkd.XPrv
192 copy(newXPrv[:], xprvBytes[:])
194 msg, err := hex.DecodeString(signData)
198 sig := newXPrv.Sign(msg)
199 return hex.EncodeToString(sig), nil
202 // buildUnlockedTx build unlocked contract tx.
203 func buildUnlockedTx(s *Server, guid, contractUTXOID, contractAsset, receiver string, fee, spendWalletAmount, confirmations, contractAmount uint64) (*buildTxResp, error) {
205 spendUTXOInput := SpendUTXOInput{
207 OutputID: contractUTXOID,
210 spendWalletInput := SpendWalletInput{
211 Type: "spend_wallet",
213 Amount: spendWalletAmount,
217 controlAddressOutput := ControlAddressOutput{
218 Type: "control_address",
219 Amount: contractAmount,
220 AssetID: contractAsset,
224 var inputs, outputs []interface{}
225 inputs = append(inputs, spendUTXOInput, spendWalletInput)
226 outputs = append(outputs, controlAddressOutput)
227 payload, err := json.Marshal(buildTxReq{
230 Confirmations: confirmations,
238 fmt.Println("build unlocked contract tx:", string(payload))
240 res := new(buildTxResp)
241 if err := s.request(buildTransactionURL, payload, res); err != nil {
248 // submitUnlockedPayment submit raw transaction and return transaction ID.
249 func submitUnlockedPayment(s *Server, guid, rawTx, memo, spendWalletSig string, spendUTXOSignatures []string) (string, error) {
250 // spendUTXOSignatures := append([]string{}, preimage, spendUTXOSig, "")
251 spendWalletSignatures := append([]string{}, spendWalletSig)
252 sigs := append([][]string{}, spendUTXOSignatures, spendWalletSignatures)
254 payload, err := json.Marshal(submitPaymentReq{
264 fmt.Println("submitUnlockedPayment:", string(payload))
266 res := new(submitPaymentResp)
267 if err := s.request(submitTransactionURL, payload, res); err != nil {
274 // buildCallTradeoffTx build unlocked tradeoff contract tx.
275 func buildCallTradeoffTx(s *Server, guid, contractUTXOID, contractAsset, seller, assetRequested string, fee, spendWalletAmount, confirmations, contractAmount, amountRequested uint64) (*buildTxResp, error) {
277 spendUTXOInput := SpendUTXOInput{
279 OutputID: contractUTXOID,
282 spendWalletInput := SpendWalletInput{
283 Type: "spend_wallet",
285 Amount: spendWalletAmount,
288 spendWalletUnlockTradeoffInput := SpendWalletInput{
289 Type: "spend_wallet",
290 AssetID: assetRequested,
291 Amount: amountRequested,
295 controlProgramOutput := ControlProgramOutput{
296 Type: "control_program",
297 Amount: amountRequested,
298 AssetID: assetRequested,
299 ControlProgram: seller,
302 var inputs, outputs []interface{}
303 inputs = append(inputs, spendUTXOInput, spendWalletInput, spendWalletUnlockTradeoffInput)
304 outputs = append(outputs, controlProgramOutput)
305 payload, err := json.Marshal(buildTxReq{
308 Confirmations: confirmations,
316 fmt.Println("build unlocked contract tx:", string(payload))
318 res := new(buildTxResp)
319 if err := s.request(buildTransactionURL, payload, res); err != nil {