-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtransaction.go
427 lines (379 loc) · 12 KB
/
transaction.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2022 The Cardano Community Authors
package koios
import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/shopspring/decimal"
)
// introduces breaking change since v1.3.0
type (
TX struct {
EUTxO
TxInfo
}
// UTxO model holds inputs and outputs for given UTxO.
EUTxO struct {
/// TxHash is hash of transaction.
TxHash TxHash `json:"tx_hash,omitempty"`
// Inputs An array with details about inputs used in a transaction.
Inputs []UTxO `json:"inputs" cbor:"0,keyasint"`
// Outputs An array with details about outputs from the transaction.
Outputs []UTxO `json:"outputs" cbor:"1,keyasint"`
}
// TxMetalabel
TxMetalabel struct {
// A distinct known metalabel
Key string `json:"key"`
}
UTxO struct {
// Hash of this transaction.
TxHash TxHash `json:"tx_hash"`
// Index of output UTxO.
TxIndex int `json:"tx_index"`
// Address A Cardano payment/base address (bech32 encoded)
Address *Address `json:"address,omitempty"`
// Total sum of ADA on the UTxO
Value decimal.Decimal `json:"value"`
// StakeAddress for transaction's output UTxO.
StakeAddress *Address `json:"stake_addr,omitempty"`
// where funds were sent or change to be returned.
PaymentCred *PaymentCredential `json:"payment_cred,omitempty"`
EpochNo EpochNo `json:"epoch_no"`
BlockHeight uint64 `json:"block_height"`
BlockTime Timestamp `json:"block_time"`
DatumHash DatumHash `json:"datum_hash"`
InlineDatum any `json:"inline_datum"`
ReferenceScript any `json:"reference_script"`
// An array of assets to be included in output UTxO.
AssetList []Asset `json:"asset_list,omitempty"`
IsSpent bool `json:"is_spent,omitempty"`
}
// TxsWithdrawal withdrawal record in transaction.
TxsWithdrawal struct {
// Amount is withdrawal amount in lovelaces.
Amount decimal.Decimal `json:"amount,omitempty"`
// StakeAddress fo withdrawal.
StakeAddress Address `json:"stake_addr,omitempty"`
}
TxListItem struct {
TxHash TxHash `json:"tx_hash"`
BlockHeight uint64 `json:"block_height"`
BlockTime Timestamp `json:"block_time"`
EpochNo EpochNo `json:"epoch_no"`
}
// TxInfo transaction info.
TxInfo struct {
// BlockHash is hash of the block in which transaction was included.
BlockHash BlockHash `json:"block_hash"`
// BlockHeight is block number on chain where transaction was included.
BlockHeight int `json:"block_height"`
// Epoch number.
EpochNo EpochNo `json:"epoch_no"`
// EpochSlot is slot number within epoch.
EpochSlot Slot `json:"epoch_slot"`
// AbsoluteSlot is overall slot number (slots from genesis block of chain).
AbsoluteSlot Slot `json:"absolute_slot"`
// TxTimestamp is timestamp when block containing transaction was created.
TxTimestamp Timestamp `json:"tx_timestamp"`
// TxBlockIndex is index of transaction within block.
TxBlockIndex int `json:"tx_block_index"`
// TxSize is transaction size in bytes.
TxSize int `json:"tx_size"`
// TotalOutput is total sum of all transaction outputs (in lovelaces).
TotalOutput decimal.Decimal `json:"total_output"`
// Fee is total transaction fee (in lovelaces).
Fee decimal.Decimal `json:"fee" cbor:"2,keyasint"`
// Deposit is total deposits included in transaction (for example,
// if it is registering a pool/key).
Deposit decimal.Decimal `json:"deposit"`
// InvalidAfter is slot number after which transaction cannot be validated.
InvalidAfter Timestamp `json:"invalid_after,omitempty" cbor:"3,keyasint,omitempty"`
// InvalidBefore is slot number before which transaction cannot be validated.
// (if supplied, else 0)
InvalidBefore Timestamp `json:"invalid_before,omitempty" cbor:"8,keyasint,omitempty"`
// CollateralInputs An array of collateral inputs needed when dealing with smart contracts.
CollateralInputs []UTxO `json:"collateral_inputs,omitempty"`
// CollateralOutput
CollateralOutput *UTxO `json:"collateral_output,omitempty"`
// CollateralInputs An array of collateral inputs needed when dealing with smart contracts.
ReferenceInputs []UTxO `json:"reference_inputs,omitempty"`
// Array of withdrawals with-in a transaction (if any)
Withdrawals []TxsWithdrawal `json:"withdrawals,omitempty"`
// AssetsMinted An array of minted assets with-in a transaction (if any).
AssetsMinted []Asset `json:"assets_minted,omitempty"`
// Metadata present with-in a transaction (if any)
Metadata TxMetadata `json:"metadata,omitempty"`
// Certificates present with-in a transaction (if any)
Certificates []Certificate `json:"certificates,omitempty"`
NativeScripts []NativeScript `json:"native_scripts,omitempty"`
PlutusContracts []PlutusContract `json:"plutus_contracts,omitempty"`
}
// TxsInfosResponse represents response from `/tx_info` endpoint.
TxsInfosResponse struct {
Response
Data []TX `json:"data"`
}
// TxInfoResponse represents response from `/tx_info` endpoint.
// when requesting info about single transaction.
TxInfoResponse struct {
Response
Data TX `json:"data"`
}
// TxUTxOsResponse represents response from `/tx_utxos` endpoint.
TxUTxOsResponse struct {
Response
Data *EUTxO `json:"data"`
}
// TxsUTxOsResponse represents response from `/tx_utxos` endpoint.
TxsUTxOsResponse struct {
Response
Data []EUTxO `json:"data"`
}
// TxMetadata transaction metadata lookup res for `/tx_metadata` endpoint.
TxMetadata map[string]json.RawMessage
TxMetadataOf struct {
TxHash TxHash `json:"tx_hash"`
Metadata TxMetadata `json:"metadata,omitempty"`
}
// SubmitSignedTxResponse represents response from `/submittx` endpoint.
SubmitSignedTxResponse struct {
Response
Data TxHash `json:"data"`
}
// TxBodyJSON used to Unmarshal built transactions.
TxBodyJSON struct {
Type string `json:"type"`
Description string `json:"description"`
CborHex string `json:"cborHex"`
}
// TxMetadataResponse represents response from `/tx_metadata` endpoint.
TxMetadataResponse struct {
Response
Data *TxMetadataOf `json:"data"`
}
// TxsMetadataResponse represents response from `/tx_metadata` endpoint.
TxsMetadataResponse struct {
Response
Data []TxMetadataOf `json:"data"`
}
// TxMetaLabelsResponse represents response from `/tx_metalabels` endpoint.
TxMetaLabelsResponse struct {
Response
Data []TxMetalabel `json:"data"`
}
// TxStatus is tx_status enpoint response.
TxStatus struct {
TxHash TxHash `json:"tx_hash"`
Confirmations uint64 `json:"num_confirmations"`
}
// TxsStatusesResponse represents response from `/tx_status` endpoint.
TxsStatusesResponse struct {
Response
Data []TxStatus `json:"data"`
}
// TxStatusResponse represents response from `/tx_status` endpoint.
TxStatusResponse struct {
Response
Data *TxStatus `json:"data"`
}
UTxORef string
UTxOInfoResponse struct {
Response
Data []UTxO `json:"data"`
}
)
// GetTxInfo returns detailed information about transaction.
func (c *Client) GetTxInfo(
ctx context.Context,
txs []TxHash,
opts *RequestOptions,
) (*TxsInfosResponse, error) {
res := &TxsInfosResponse{}
if len(txs) == 0 || len(txs[0]) == 0 {
err := ErrNoTxHash
res.applyError(nil, err)
return res, err
}
rsp, err := c.request(ctx, &res.Response, "POST", "/tx_info", txHashesPL(txs), opts)
if err != nil {
return res, err
}
return res, ReadAndUnmarshalResponse(rsp, &res.Response, &res.Data)
}
// GetTxMetadata returns metadata information (if any) for given transaction.
func (c *Client) GetTxMetadata(
ctx context.Context,
txs []TxHash,
opts *RequestOptions,
) (*TxsMetadataResponse, error) {
res := &TxsMetadataResponse{}
if len(txs) == 0 || len(txs[0]) == 0 {
err := ErrNoTxHash
res.applyError(nil, err)
return res, err
}
rsp, err := c.request(ctx, &res.Response, "POST", "/tx_metadata", txHashesPL(txs), opts)
if err != nil {
return res, err
}
return res, ReadAndUnmarshalResponse(rsp, &res.Response, &res.Data)
}
// GetTxMetaLabels retruns a list of all transaction metalabels.
func (c *Client) GetTxMetaLabels(
ctx context.Context,
opts *RequestOptions,
) (*TxMetaLabelsResponse, error) {
res := &TxMetaLabelsResponse{}
rsp, err := c.request(ctx, &res.Response, "GET", "/tx_metalabels", nil, opts)
if err != nil {
return res, err
}
return res, ReadAndUnmarshalResponse(rsp, &res.Response, &res.Data)
}
// SubmitSignedTx Submit an transaction to the network.
func (c *Client) SubmitSignedTx(
ctx context.Context,
stx TxBodyJSON,
opts *RequestOptions,
) (*SubmitSignedTxResponse, error) {
res := &SubmitSignedTxResponse{}
var method = "POST"
cborb, err := hex.DecodeString(stx.CborHex)
if err != nil {
res.RequestMethod = method
res.StatusCode = 400
res.applyError(nil, err)
return res, err
}
if opts == nil {
opts = c.NewRequestOptions()
}
opts.HeaderSet("Content-Type", "application/cbor")
opts.HeaderSet("Content-Length", fmt.Sprint(len(cborb)))
rsp, err := c.request(ctx, &res.Response, method, "/submittx", bytes.NewBuffer(cborb), opts)
if err != nil {
body, _ := ReadResponseBody(rsp)
res.applyError(body, err)
return res, err
}
body, err := ReadResponseBody(rsp)
res.Data = TxHash(strings.Trim(string(body), "\""))
return res, err
}
// GetTxStatus returns status of transaction(s).
func (c *Client) GetTxStatus(
ctx context.Context,
txs []TxHash,
opts *RequestOptions,
) (*TxsStatusesResponse, error) {
res := &TxsStatusesResponse{}
if len(txs) == 0 {
err := ErrNoTxHash
res.applyError(nil, err)
return res, err
}
rsp, err := c.request(ctx, &res.Response, "POST", "/tx_status", txHashesPL(txs), opts)
if err != nil {
return res, err
}
return res, ReadAndUnmarshalResponse(rsp, &res.Response, &res.Data)
}
func (c *Client) GetUTxOInfo(
ctx context.Context,
refs []UTxORef,
extended bool,
opts *RequestOptions,
) (*UTxOInfoResponse, error) {
res := &UTxOInfoResponse{}
if len(refs) == 0 {
err := ErrNoUTxORef
res.applyError(nil, err)
return res, err
}
if opts == nil {
opts = c.NewRequestOptions()
}
rsp, err := c.request(ctx, &res.Response, "POST", "/utxo_info", utxoRefsPL(refs, extended), opts)
if err != nil {
res.applyError(nil, err)
return res, err
}
return res, ReadAndUnmarshalResponse(rsp, &res.Response, &res.Data)
}
func txHashesPL(txs []TxHash) io.Reader {
var payload = struct {
TxHashes []TxHash `json:"_tx_hashes"`
}{txs}
rpipe, w := io.Pipe()
go func() {
_ = json.NewEncoder(w).Encode(payload)
defer w.Close()
}()
return rpipe
}
func utxoRefsPL(refs []UTxORef, extended bool) io.Reader {
var payload = struct {
UtxORefs []UTxORef `json:"_utxo_refs"`
Extended bool `json:"_extended"`
}{refs, extended}
rpipe, w := io.Pipe()
go func() {
_ = json.NewEncoder(w).Encode(payload)
defer w.Close()
}()
return rpipe
}
type metaArrayItem struct {
// Key is metadata (index).
Key string `json:"key,omitempty"`
// JSON containing details about metadata within transaction.
JSON json.RawMessage `json:"json,omitempty"`
}
func (m *TxMetadata) UnmarshalJSON(b []byte) error {
if len(b) == 0 || string(b) == "[]" {
return nil
}
var txMetadata map[string]json.RawMessage
var txMetadataArray []metaArrayItem
if err2 := json.Unmarshal(b, &txMetadataArray); err2 != nil {
if err3 := json.Unmarshal(b, &txMetadata); err3 == nil {
*m = txMetadata
return nil
}
return fmt.Errorf("unmarshal metadata: %w", err2)
}
if len(txMetadataArray) == 0 {
return nil
}
if len(txMetadataArray) == 1 && len(txMetadataArray[0].Key) == 0 {
return nil
}
(*m) = make(TxMetadata)
for _, meta := range txMetadataArray {
(*m)[meta.Key] = meta.JSON
}
return nil
}
type metaListItem struct {
TxHash TxHash `json:"tx_hash"`
Metadata map[string]json.RawMessage `json:"metadata"`
}
func (m *TxMetadataOf) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
return nil
}
var data metaListItem
if err := json.Unmarshal(b, &data); err != nil {
return fmt.Errorf("unmarshal metadata list: %w", err)
}
m.TxHash = data.TxHash
m.Metadata = data.Metadata
return nil
}