Skip to content

Commit

Permalink
feat: prep tx struct for tx submit feature
Browse files Browse the repository at this point in the history
Signed-off-by: Marko Kungla <marko.kungla@gmail.com>
  • Loading branch information
mkungla committed Oct 3, 2022
1 parent 74ecbb2 commit df53628
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 71 deletions.
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
// Deprecated: Upgrade to github.com/cardano-community/koios-go-client/v2
// versions < v2 do not work with Koios API after koios v1.0.7 breaking changes.
module github.com/cardano-community/koios-go-client
module github.com/cardano-community/koios-go-client // imports as package "koios"

go 1.16

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fxamacker/cbor/v2 v2.4.0
github.com/kr/text v0.2.0 // indirect
github.com/shopspring/decimal v1.3.1
github.com/stretchr/testify v1.7.1
golang.org/x/text v0.3.7
golang.org/x/time v0.0.0-20220411224347-583f2d630306
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
20 changes: 17 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
14 changes: 4 additions & 10 deletions koios.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ var (
ErrSchema = errors.New("scheme must be http or https")
ErrReqOptsAlreadyUsed = errors.New("request options can only be used once")
ErrUnexpectedResponseField = errors.New("unexpected response field")
ZeroLovelace = NewLovelace(0, 1) //nolint: gochecknoglobals
ErrUTxOInputAlreadyUsed = errors.New("UTxO already used")

ZeroLovelace = NewLovelace(0, 1) //nolint: gochecknoglobals
)

// introduces breaking change since v1.3.0
Expand All @@ -84,9 +86,6 @@ type (
apply func(*Client) error
}

// Address defines type for _address.
Address string

// PaymentCredential type def.
PaymentCredential string

Expand Down Expand Up @@ -134,7 +133,7 @@ type (
PaymentAddr struct {
// Bech32 is Cardano payment/base address (bech32 encoded)
// for transaction's or change to be returned.
Bech32 string `json:"bech32"`
Bech32 Address `json:"bech32"`

// Payment credential.
Cred PaymentCredential `json:"cred"`
Expand Down Expand Up @@ -296,11 +295,6 @@ func New(opts ...Option) (*Client, error) {
return c, nil
}

// String returns Address as string.
func (v Address) String() string {
return string(v)
}

// String returns PaymentCredential as string.
func (v PaymentCredential) String() string {
return string(v)
Expand Down
38 changes: 30 additions & 8 deletions lovelace.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package koios

import (
"regexp"

"github.com/shopspring/decimal"
)

Expand All @@ -39,11 +41,31 @@ func NewLovelaceFromString(value string) (Lovelace, error) {
// return err
// }

// func NewLovelaceFromBigInt(value *big.Int, exp int32) Lovelace
// func NewLovelaceFromFloat(value float64) Lovelace
// func NewLovelaceFromFloat32(value float32) Lovelace
// func NewLovelaceFromFloatWithExponent(value float64, exp int32) Lovelace
// func NewLovelaceFromFormattedString(value string, replRegexp *regexp.Regexp) (Lovelace, error)
// func NewLovelaceFromInt(value int64) Lovelace
// func NewLovelaceFromInt32(value int32) Lovelace
// func NewLovelaceFromString(value string) (Lovelace, error)
func NewLovelaceFromFloat(value float64) Lovelace {
return Lovelace{Decimal: decimal.NewFromFloat(value)}
}

func NewLovelaceFromFloat32(value float32) Lovelace {
return Lovelace{Decimal: decimal.NewFromFloat32(value)}
}

func NewLovelaceFromFloatWithExponent(value float64, exp int32) Lovelace {
return Lovelace{Decimal: decimal.NewFromFloatWithExponent(value, exp)}
}

func NewLovelaceFromFormattedString(value string, replRegexp *regexp.Regexp) (Lovelace, error) {
val, err := decimal.NewFromFormattedString(value, replRegexp)
return Lovelace{Decimal: val}, err
}

func NewLovelaceFromInt(value int64) Lovelace {
return Lovelace{Decimal: decimal.NewFromInt(value)}
}

func NewLovelaceFromInt32(value int32) Lovelace {
return Lovelace{Decimal: decimal.NewFromInt32(value)}
}

func NewLovelaceFromDecimal(value decimal.Decimal) Lovelace {
return Lovelace{Decimal: value}
}
119 changes: 77 additions & 42 deletions transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,26 @@ import (
"encoding/json"
"fmt"
"io"

"github.com/fxamacker/cbor/v2"
)

// introduces breaking change since v1.3.0

type (
TX struct {
/// TxHash is hash of transaction.
TxHash TxHash `json:"tx_hash"`
// BlockHeight is block number on chain where transaction was included.
BlockHeight int `json:"block_height"`
// BlockTime is time of the block.
BlockTime Time `json:"block_time"`
Epoch EpochNo `json:"epoch_no,omitempty"`
TxInfo
}

// UTxO model holds inputs and outputs for given UTxO.
UTxO struct {
/// TxHash is hash of transaction.
TxHash TxHash `json:"tx_hash"`
TxHash TxHash `json:"tx_hash,omitempty"`

// Inputs An array with details about inputs used in a transaction.
Inputs []TxInput `json:"inputs"`
Inputs []TxInput `json:"inputs" cbor:"0,keyasint"`
// Outputs An array with details about outputs from the transaction.
Outputs []TxOutput `json:"outputs"`
Outputs []TxOutput `json:"outputs" cbor:"1,keyasint"`
}

// TxMetalabel defines model for tx_metalabels.
Expand All @@ -58,10 +54,10 @@ type (
// TxInput an transaxtion input.
TxInput struct {
// An array of assets contained on input UTxO.
AssetList []Asset `json:"asset_list"`
AssetList []Asset `json:"asset_list,omitempty"`

// input UTxO.
PaymentAddr PaymentAddr `json:"payment_addr"`
PaymentAddr PaymentAddr `json:"payment_addr,omitempty"`

// StakeAddress for transaction's input UTxO.
StakeAddress StakeAddress `json:"stake_addr,omitempty"`
Expand All @@ -70,7 +66,7 @@ type (
TxHash TxHash `json:"tx_hash"`

// Index of input UTxO on the mentioned address used for input.
TxIndex int `json:"tx_index"`
TxIndex uint32 `json:"tx_index"`

// Balance on the selected input transaction.
Value Lovelace `json:"value"`
Expand All @@ -79,10 +75,10 @@ type (
// TxOutput an transaxtion output.
TxOutput struct {
// An array of assets to be included in output UTxO.
AssetList []Asset `json:"asset_list"`
AssetList []Asset `json:"asset_list,omitempty"`

// where funds were sent or change to be returned.
PaymentAddr PaymentAddr `json:"payment_addr"`
PaymentAddr PaymentAddr `json:"payment_addr,omitempty"`

// StakeAddress for transaction's output UTxO.
StakeAddress StakeAddress `json:"stake_addr,omitempty"`
Expand All @@ -91,7 +87,7 @@ type (
TxHash TxHash `json:"tx_hash"`

// Index of output UTxO.
TxIndex int `json:"tx_index"`
TxIndex uint32 `json:"tx_index"`

// Total sum on the output address.
Value Lovelace `json:"value"`
Expand All @@ -116,70 +112,63 @@ type (

// TxInfo transaction info.
TxInfo struct {
// TxHash is hash of transaction.
TxHash TxHash `json:"tx_hash"`
UTxO

// BlockHash is hash of the block in which transaction was included.
BlockHash BlockHash `json:"block_hash"`
BlockHash BlockHash `json:"block_hash,omitempty"`

// BlockHeight is block number on chain where transaction was included.
BlockHeight int `json:"block_height"`
BlockHeight uint64 `json:"block_height,omitempty"`

// Epoch number.
Epoch EpochNo `json:"epoch"`
Epoch EpochNo `json:"epoch,omitempty"`

// EpochSlot is slot number within epoch.
EpochSlot int `json:"epoch_slot"`
EpochSlot uint32 `json:"epoch_slot,omitempty"`

// AbsoluteSlot is overall slot number (slots from genesis block of chain).
AbsoluteSlot int `json:"absolute_slot"`
AbsoluteSlot uint64 `json:"absolute_slot,omitempty"`

// TxTimestamp is timestamp when block containing transaction was created.
TxTimestamp Time `json:"tx_timestamp"`
TxTimestamp string `json:"tx_timestamp,omitempty"`

// TxBlockIndex is index of transaction within block.
TxBlockIndex int `json:"tx_block_index"`
TxBlockIndex uint32 `json:"tx_block_index,omitempty"`

// TxSize is transaction size in bytes.
TxSize int `json:"tx_size"`
TxSize uint32 `json:"tx_size,omitempty"`

// TotalOutput is total sum of all transaction outputs (in lovelaces).
TotalOutput Lovelace `json:"total_output"`
TotalOutput Lovelace `json:"total_output,omitempty"`

// Fee is total transaction fee (in lovelaces).
Fee Lovelace `json:"fee"`
Fee Lovelace `json:"fee,omitempty" cbor:"2,keyasint"`

// Deposit is total deposits included in transaction (for example,
// if it is registering a pool/key).
Deposit Lovelace `json:"deposit"`
Deposit Lovelace `json:"deposit,omitempty"`

// InvalidAfter is slot number after which transaction cannot be validated.
InvalidAfter int `json:"invalid_after,omitempty"`
InvalidAfter uint64 `json:"invalid_after,omitempty" cbor:"3,keyasint,omitempty"`

// InvalidBefore is slot number before which transaction cannot be validated.
// (if supplied, else 0)
InvalidBefore int `json:"invalid_before,omitempty"`

// Inputs An array with details about inputs used in a transaction
Inputs []TxInput `json:"inputs"`

// Outputs An array with details about outputs from the transaction.
Outputs []TxOutput `json:"outputs,omitempty"`
InvalidBefore uint64 `json:"invalid_before,omitempty" cbor:"8,keyasint,omitempty"`

// AssetsMinted An array of minted assets with-in a transaction (if any).
AssetsMinted []Asset `json:"assets_minted"`
AssetsMinted []Asset `json:"assets_minted,omitempty"`

// Collaterals An array of collateral inputs needed when dealing with smart contracts.
Collaterals []TxInput `json:"collaterals"`
Collaterals []TxInput `json:"collaterals,omitempty"`

// Metadata present with-in a transaction (if any)
Metadata []TxInfoMetadata `json:"metadata"`
Metadata []TxInfoMetadata `json:"metadata,omitempty"`

// Array of withdrawals with-in a transaction (if any)
Withdrawals []TxsWithdrawal `json:"withdrawals"`
Withdrawals []TxsWithdrawal `json:"withdrawals,omitempty"`

// Certificates present with-in a transaction (if any)
Certificates []Certificate `json:"certificates"`
Certificates []Certificate `json:"certificates,omitempty"`
}

// TxsInfosResponse represents response from `/tx_info` endpoint.
Expand Down Expand Up @@ -409,6 +398,8 @@ func (c *Client) SubmitSignedTx(

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)
Expand Down Expand Up @@ -451,6 +442,11 @@ func (c *Client) GetTxsStatuses(
return res, ReadAndUnmarshalResponse(rsp, &res.Response, &res.Data)
}

// NewTxWithAutoFee.
func NewTransaction() *TX {
return &TX{}
}

func txHashesPL(txs []TxHash) io.Reader {
var payload = struct {
TxHashes []TxHash `json:"_tx_hashes"`
Expand All @@ -462,3 +458,42 @@ func txHashesPL(txs []TxHash) io.Reader {
}()
return rpipe
}

// AddUTxO adds utxo inputs and otputs to transaction
// Useful when composing batch transaction.
func (tx *TX) AddUTxO(utxo UTxO) error {
for _, in := range utxo.Inputs {
// check that UTxO inputs are not already used
for _, tin := range tx.Inputs {
if in.TxHash == tin.TxHash && in.TxIndex == tin.TxIndex {
return fmt.Errorf("%w: %s#%d", ErrUTxOInputAlreadyUsed, in.TxHash, in.TxIndex)
}
}
tx.Inputs = append(tx.Inputs, in)
}

tx.Outputs = append(tx.Outputs, utxo.Outputs...)

return nil
}

// CalculateSharedFee calculates fee and shares fee between transaction outputs.
// Optionally you can provide destination addresses which will not share the fee.
// e.g
// most cases you would exclude your own address so that only
// external receivers pay the fee. Useful when using this lib in faucet.
func (tx *TX) CalculateSharedFee(params EpochParams, exclude ...Address) error {
return nil
}

func (out *TxOutput) MarshalCBOR() ([]byte, error) {
if len(out.PaymentAddr.Bech32) == 0 {
return nil, fmt.Errorf("cbor: %w", ErrNoAddress)
}

// handle assets
// if len(o.Assets) > 0 {
// return cbor.Marshal([]interface{}{o.Address.Bytes(), []interface{}{o.Amount, o.Assets}})
// }
return cbor.Marshal([]interface{}{out.PaymentAddr.Bech32.Bytes(), out.Value.IntPart()})
}
Loading

0 comments on commit df53628

Please sign in to comment.