Skip to content

Commit

Permalink
Split doc into Cardano.Api.Experimental.Tx and Cardano.Api.Tx.Body
Browse files Browse the repository at this point in the history
  • Loading branch information
palas committed Dec 11, 2024
1 parent bd4f6ba commit 526d3ef
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 218 deletions.
126 changes: 125 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,131 @@
{-# 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.

-- ** 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

-- |
-- 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

-- |
-- 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
132 changes: 116 additions & 16 deletions cardano-api/internal/Cardano/Api/Tx/Body.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,120 @@
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}

-- | Transaction bodies
module Cardano.Api.Tx.Body
( parseTxId

-- * Transaction bodies
( -- * Creating a 'TxBodyContent'

-- |
--
-- In order to create a transaction, we first need to define the contents of its body. In this section,
-- we will see how to create a 'TxBodyContent' for a simple transaction using the API.
--
-- In this example, 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.Experimental as Exp -- the experimental API
-- @
--
-- 'TxBodyContent' datatype provides lots of fields, because transactions can serve multiple
-- purposes, but the function 'defaultTxBodyContent' exported from 'Cardano.Api' already provides
-- a base 'TxBodyContent' with all fields set to their default values that we can use as a starting point
-- in order not to have to set all fields manually.
--
-- The 'defaultTxBodyContent' takes, as the only parameter, the 'ShelleyBasedEra' witness for the era
-- we are working with. For example, if we are working with the 'ConwayEra', we can use 'shelleyBasedEra'
-- available in 'Cardano.Api', as follows:
--
-- @
-- let sbe :: Api.ShelleyBasedEra Api.ConwayEra = Api.shelleyBasedEra
-- @
--
-- We can also derive it from 'ConwayEra' from 'Cardano.Api.Experimental' by using the 'convert' function:
--
-- @
-- let era = Exp.ConwayEra
-- let sbe = Api.convert era
-- @
--
-- Let's see what creating a simple 'TxBodyContent' would look like.
--
-- First, we choose a transaction output to spend (a UTxO). We specify which UTxO to spend by
-- providing the transaction id and the index of the output in that transaction that we want
-- to spend.
--
-- To specify the transaction id, we can use the 'deserialiseFromRawBytesHex' function on the
-- hexadecimal representation of the hash of the transaction. For example:
--
-- @
-- let (Right srcTxId) = Api.deserialiseFromRawBytesHex Api.AsTxId "be6efd42a3d7b9a00d09d77a5d41e55ceaf0bd093a8aa8a893ce70d9caafd978"
-- @
--
-- Of course, in real code, the failure case should be handled properly.
--
-- To specify the transaction index, we can use the 'TxIx' constructor. For example:
--
-- @
-- let srcTxIx = Api.TxIx 0
-- @
--
-- Now we combine both to create a 'TxIn' value and we pair it with a witness requirement using 'BuildTxWith' :
--
-- @
-- let txIn = ( Api.TxIn srcTxId srcTxIx
-- , Api.BuildTxWith (Api.KeyWitness Api.KeyWitnessForSpending)
-- )
-- @
--
-- Next, let's specify the address of the recipient of the transaction. If we have the Bech32 representation,
-- we can use the 'deserialiseAddress' function to get the 'AddressInEra' type. For example:
--
-- @
-- let (Just destAddress) = Api.deserialiseAddress (Api.AsAddressInEra eraAsType) "addr_test1vzpfxhjyjdlgk5c0xt8xw26avqxs52rtf69993j4tajehpcue4v2v"
-- @
--
-- Now we can create a 'TxOut' value. For simplicity, we will assume the output is a simple payment output
-- of 10 ADA, with no datum or reference script attached to it:
--
-- @
-- let txOut = Api.TxOut
-- destAddress
-- (Api.lovelaceToTxOutValue sbe 10_000_000)
-- Api.TxOutDatumNone
-- Script.ReferenceScriptNone
-- @
--
-- We must also set the fee for the transaction. For example, let's set it to 2 ADA:
--
-- @
-- let txFee = Api.TxFeeExplicit sbe 2_000_000
-- @
--
-- Finally, we can create the 'TxBodyContent' by using the 'defaultTxBodyContent' function and
-- putting everything together:
--
-- @
-- let txBodyContent = Api.defaultTxBodyContent sbe
-- & Api.setTxIns [txIn]
-- & Api.setTxOuts [txOut]
-- & Api.setTxFee txFee
-- @
--
-- The 'txBodyContent' can now be used to create a transaction either using the old or the new API.

-- * Contents
parseTxId

-- ** Transaction bodies
, TxBody (.., TxBody)
, createTransactionBody
, createAndValidateTransactionBody
, TxBodyContent (..)

-- * Byron only
-- ** Byron only
, makeByronTransactionBody

-- ** Transaction body builders
-- *** Transaction body builders
, defaultTxBodyContent
, defaultTxFee
, defaultTxValidityUpperBound
Expand Down Expand Up @@ -68,20 +168,20 @@ module Cardano.Api.Tx.Body
, txScriptValidityToIsValid
, txScriptValidityToScriptValidity

-- * Transaction Ids
-- ** Transaction Ids
, TxId (..)
, getTxId
, getTxIdByron
, getTxIdShelley

-- * Transaction inputs
-- ** Transaction inputs
, TxIn (..)
, TxIns
, TxIx (..)
, genesisUTxOPseudoTxIn
, getReferenceInputsSizeForTxIds

-- * Transaction outputs
-- ** Transaction outputs
, CtxTx
, CtxUTxO
, TxOut (..)
Expand All @@ -96,7 +196,7 @@ module Cardano.Api.Tx.Body
, TxOutInAnyEra (..)
, txOutInAnyEra

-- * Other transaction body types
-- ** Other transaction body types
, TxInsCollateral (..)
, TxInsReference (..)
, TxReturnCollateral (..)
Expand All @@ -119,23 +219,23 @@ module Cardano.Api.Tx.Body
, mkTxProposalProcedures
, convProposalProcedures

-- ** Building vs viewing transactions
-- *** Building vs viewing transactions
, BuildTxWith (..)
, BuildTx
, ViewTx
, buildTxWithToMaybe

-- * Inspecting 'ScriptWitness'es
-- ** Inspecting 'ScriptWitness'es
, AnyScriptWitness (..)
, ScriptWitnessIndex (..)
, renderScriptWitnessIndex
, collectTxBodyScriptWitnesses
, toScriptIndex

-- * Conversion to inline data
-- ** Conversion to inline data
, scriptDataToInlineDatum

-- * Internal conversion functions & types
-- ** Internal conversion functions & types
, convCertificates
, convCollateralTxIns
, convExtraKeyWitnesses
Expand Down Expand Up @@ -170,12 +270,12 @@ module Cardano.Api.Tx.Body
, fromLedgerTxOuts
, renderTxIn

-- * Misc helpers
-- ** Misc helpers
, calculateExecutionUnitsLovelace
, orderStakeAddrs
, orderTxIns

-- * Data family instances
-- ** Data family instances
, AsType (AsTxId, AsTxBody, AsByronTxBody, AsShelleyTxBody, AsMaryTxBody)
, getTxBodyContent
-- Temp
Expand Down
Loading

0 comments on commit 526d3ef

Please sign in to comment.