Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added examples of transaction creation to Haddock #698

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cardano-api/cardano-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ test-suite cardano-api-test
Test.Cardano.Api.Envelope
Test.Cardano.Api.EpochLeadership
Test.Cardano.Api.Eras
Test.Cardano.Api.Experimental
Test.Cardano.Api.Genesis
Test.Cardano.Api.IO
Test.Cardano.Api.Json
Expand Down
137 changes: 136 additions & 1 deletion cardano-api/internal/Cardano/Api/Experimental/Tx.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,142 @@
{-# LANGUAGE UndecidableInstances #-}

module Cardano.Api.Experimental.Tx
( UnsignedTx (..)
( -- * Creating transactions using the new and the old API

-- |
-- Both the old and the new API can be used to create transactions, and
-- it is possible to transform a transaction created in one format to the other
-- since they have the same representation underneath. But we will be moving
-- towards using the new API and deprecating the old way, since the latter is
-- simpler, closer to the ledger, and easier to maintain.
--
-- In both the new and the old API, in order to construct a transaction,
-- we need to construct a 'TxBodyContent', and we will need at least a
-- witness (for example, a 'ShelleyWitnessSigningKey'), to sign the transaction.
-- This hasn't changed.
--
-- In the following examples, we are using the following qualified modules:
--
-- @
-- import qualified Cardano.Api as Api -- the general `cardano-api` exports (including the old API)
-- import qualified Cardano.Api.Script as Script -- types related to scripts (Plutus and native)
-- import qualified Cardano.Api.Ledger as Ledger -- cardano-ledger re-exports
-- import qualified Cardano.Api.Experimental as Exp -- the experimental API
-- @
--
-- You can find a compilable version of these examples in "Test.Cardano.Api.Experimental".

-- ** Creating a 'TxBodyContent'

-- |
-- Independently of whether we use the Experimental or the traditoinal API, we need to create a 'TxBodyContent'.
--
-- You can see how to do this in the documentation of the "Cardano.Api.Tx.Body" module.

-- ** Balancing a transaction

-- |
-- If we have a UTxO with exactly 12 ADA, and 2 ADA is enough for the fees, we could just construct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can word this better and we should think of this in terms of consumption and production (see preservation of value in the Shelley spec) if we want to be thorough. This is in the Shelley spec:
image

You would need to look through the other specs to confirm if these functions have been modified (likely with the introduction of multi-assets). We should say something like:

"A transaction is considered balanced if the value consumed is equivalent to the value produced. In the simplest terms a transaction that simply spends lovelace needs to be concerned with the total lovelace that exists at the inputs, the output(s) and the transaction fee. In other words:

inputs = outputs + fee"

You can then walk through the simple example of manually balancing a tx and point out that although the transaction is valid, you are overpaying for fees.

Overpaying for fees is not an invalid transaction.

-- the transaction like in the previous section directly, and it could be a valid transaction. But still,
-- even if we have exactly 12 ADA, it is unlikely the fees required are exactly 2 ADA, so either we made
-- an invalid transaction, or we are wasting ADA on fees. Also, we may not always want to send all the ADA
-- in the UTxO. So that is were transaction balancing comes in.
--
-- You can see how to balance a transaction in the documentation of the "Cardano.Api.Fees" module.

-- ** Creating a 'ShelleyWitnessSigningKey'

-- |
-- To sign the transaction, we need a witness. For example, a 'ShelleyWitnessSigningKey'.
--
-- There are several ways of doing this, and several ways of representing a signing key. But let us assume
-- we have the bech32 representation of the signing key. In that case we can use the 'deserialiseFromBech32' function
-- as follows:
--
-- @
-- let (Right signingKey) = Api.deserialiseFromBech32 (Api.AsSigningKey Api.AsPaymentKey) "addr_sk1648253w4tf6fv5fk28dc7crsjsaw7d9ymhztd4favg3cwkhz7x8sl5u3ms"
-- @
--
-- Then we simply wrap the signing key in a 'ShelleyWitnessSigningKey' value:
--
-- @
-- let witness = Api.WitnessPaymentKey signingKey
-- @
--
-- We could do it analogously if we wanted to use an extended key, for example, using 'AsPaymentExtendedKey' and 'WitnessPaymentExtendedKey'.

-- ** Creating a transaction using the old API
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put this section in the old API.


-- |
-- Now that we have a 'TxBodyContent' and a 'ShelleyWitnessSigningKey', we can create a transaction using the old API
-- easily. First, we create a transaction body using the 'createTransactionBody' function and the 'ShelleyBasedEra' witness
-- that we defined earlier.
--
-- We create the transaction body using the 'TransactionBodyContent' that we created earlier:
--
-- @
-- let (Right txBody) = Api.createTransactionBody sbe txBodyContent
-- @
--
-- Then, we sign the transaction using the 'signShelleyTransaction' function and the witness:
--
-- @
-- let oldApiSignedTx :: Api.Tx Api.ConwayEra = Api.signShelleyTransaction sbe txBody [witness]
-- @
--
-- And that is it. We have a signed transaction.

-- ** Creating a transaction using the new API

-- |
-- Now, let's see how we can create a transaction using the new API. First, we create an 'UnsignedTx' using the 'makeUnsignedTx'
-- function and the 'Era' and 'TxBodyContent' that we defined earlier:
--
-- @
-- let (Right unsignedTx) = Exp.makeUnsignedTx era txBodyContent
-- @
--
-- Then we use the key witness to witness the current unsigned transaction using the 'makeKeyWitness' function:
--
-- @
-- let transactionWitness = Exp.makeKeyWitness era unsignedTx (Api.WitnessPaymentKey signingKey)
-- @
--
-- Finally, we sign the transaction using the 'signTx' function:
--
-- @
-- let newApiSignedTx :: Ledger.Tx (Exp.LedgerEra Exp.ConwayEra) = Exp.signTx era [] [transactionWitness] unsignedTx
-- @
--
-- Where the empty list is for the bootstrap witnesses, which, in this case, we don't have any.
--
-- And that is it. We have a signed transaction.

-- ** Converting a transaction from the new API to the old API

-- |
-- If we have a transaction created using the new API, we can convert it to the old API very easily by
-- just wrapping it using the 'ShelleyTx' constructor:
--
-- @
-- let oldStyleTx :: Api.Tx Api.ConwayEra = ShelleyTx sbe newApiSignedTx
-- @

-- ** Inspecting transactions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. If it doesn't have to do with the new api, move it to the old api modules. The only thing we should be talking about with respect to the old api is how to convert between transactions from old and new.


-- |
-- For deconstructing an old style 'TxBody' into a 'TxBodyContent', we can also use the
-- 'TxBody' pattern, but this cannot be used for constructing. For that we use 'ShelleyTxBody'
-- or 'createTransactionBody', like in the example.
--
-- For extracting the 'TxBody' and the 'KeyWitness'es from an old style 'Tx', we can use
-- the lenses 'getTxBody' and 'getTxWitnesses' respectively, from "Cardano.Api".
--
-- When using a 'Tx' created using the experimental API, you can extract the 'TxBody' and
-- 'TxWits' using the lenses 'txBody' and 'txWits' respectively, from "Cardano.Api.Ledger".

-- * Contents
UnsignedTx (..)
, UnsignedTxError (..)
, makeUnsignedTx
, makeKeyWitness
Expand Down
Loading
Loading