1
{-# LANGUAGE DataKinds #-}
2
{-# LANGUAGE EmptyCase #-}
4
{-# LANGUAGE ScopedTypeVariables #-}
5
{-# LANGUAGE TypeApplications #-}
9
module Cardano.Api.Fees (
11
estimateTransactionFee,
16
import qualified Data.ByteString as BS
17
import GHC.Records (HasField (..))
18
import Numeric.Natural
20
import qualified Cardano.Binary as CBOR
21
import qualified Cardano.Chain.Common as Byron
23
import Cardano.Api.Eras
24
import Cardano.Api.NetworkId
26
import Cardano.Api.Value
29
-- ----------------------------------------------------------------------------
33
-- | For a concrete fully-constructed transaction, determine the minimum fee
34
-- that it needs to pay.
36
-- This function is simple, but if you are doing input selection then you
37
-- probably want to consider estimateTransactionFee.
39
transactionFee :: forall era.
41
=> Natural -- ^ The fixed tx fee
42
-> Natural -- ^ The tx fee per byte
45
transactionFee txFeeFixed txFeePerByte (ShelleyTx _ tx) =
48
a = toInteger txFeePerByte
49
x = getField @"txsize" tx
50
b = toInteger txFeeFixed
52
--TODO: This can be made to work for Byron txs too. Do that: fill in this case
53
-- and remove the IsShelleyBasedEra constraint.
54
transactionFee _ _ (ByronTx _) =
55
case shelleyBasedEra :: ShelleyBasedEra era of {}
58
--TODO: in the Byron case the per-byte is non-integral, would need different
59
-- parameters. e.g. a new data type for fee params, Byron vs Shelley
61
-- | This can estimate what the transaction fee will be, based on a starting
62
-- base transaction, plus the numbers of the additional components of the
63
-- transaction that may be added.
65
-- So for example with wallet coin selection, the base transaction should
66
-- contain all the things not subject to coin selection (such as script inputs,
67
-- metadata, withdrawals, certs etc)
69
estimateTransactionFee :: forall era.
72
-> Natural -- ^ The fixed tx fee
73
-> Natural -- ^ The tx fee per byte
75
-> Int -- ^ The number of extra UTxO transaction inputs
76
-> Int -- ^ The number of extra transaction outputs
77
-> Int -- ^ The number of extra Shelley key witnesses
78
-> Int -- ^ The number of extra Byron key witnesses
80
estimateTransactionFee nw txFeeFixed txFeePerByte (ShelleyTx era tx) =
81
let Lovelace baseFee = transactionFee txFeeFixed txFeePerByte (ShelleyTx era tx)
82
in \nInputs nOutputs nShelleyKeyWitnesses nByronKeyWitnesses ->
84
--TODO: this is fragile. Move something like this to the ledger and
85
-- make it robust, based on the txsize calculation.
87
extraBytes = nInputs * sizeInput
88
+ nOutputs * sizeOutput
89
+ nByronKeyWitnesses * sizeByronKeyWitnesses
90
+ nShelleyKeyWitnesses * sizeShelleyKeyWitnesses
92
in Lovelace (baseFee + toInteger txFeePerByte * toInteger extraBytes)
94
sizeInput = smallArray + uint + hashObj
95
sizeOutput = smallArray + uint + address
96
sizeByronKeyWitnesses = smallArray + keyObj + sigObj + ccodeObj + attrsObj
97
sizeShelleyKeyWitnesses = smallArray + keyObj + sigObj
102
hashObj = 2 + hashLen
111
ccodeObj = 2 + ccodeLen
114
address = 2 + addrHeader + 2 * addrHashLen
118
attrsObj = 2 + BS.length attributes
119
attributes = CBOR.serialize' $
120
Byron.mkAttributes Byron.AddrAttributes {
121
Byron.aaVKDerivationPath = Nothing,
122
Byron.aaNetworkMagic = toByronNetworkMagic nw
125
--TODO: This can be made to work for Byron txs too. Do that: fill in this case
126
-- and remove the IsShelleyBasedEra constraint.
127
estimateTransactionFee _ _ _ (ByronTx _) =
128
case shelleyBasedEra :: ShelleyBasedEra era of {}