-
Notifications
You must be signed in to change notification settings - Fork 22
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
base: master
Are you sure you want to change the base?
Changes from all commits
d8626bd
2f1b48b
7a73d58
fac4b1c
2c17d55
d794d45
4ad4f7a
d9ef2b0
d5a5a03
bd4f6ba
526d3ef
6f6d312
b79365a
47ed6cf
c9d390f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
-- 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
There was a problem hiding this comment.
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:
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.