The Pisa Fees public API documentation can be found here: https://mlabs-haskell.github.io/pisa-fees/pisa-api/web-socket-api.html
wss://server-ws-api.pisa-fees.staging.mlabs.city/ws
The Pisa balancer is a WebSocket service that can accept CBOR of an unbalanced transaction and Pisa Fees position. It balances the transaction in such a way that the fee will be paid by the Asset that the position has liquidity for, instead of Ada. The exact Assets to use for balancing are chosen by the user.
wss://indexer-server.pisa-fees.staging.mlabs.city/ws
The Pisa indexer tracks active Pisa positions and provides an API to query active positions.
wss://indexer-follower.pisa-fees.staging.mlabs.city/pisa-events
This service broadcasts changes in Pisa positions in real-time via WebSocket. As soon as the chain follower receives a new block from the Cardano node and detects new or closed positions in the block, a message will be sent to the socket. It also sends corresponding messages in case of rollback.
Making a transaction with Pisa Fees swap is a four-step process:
Create an unbalanced transaction or transaction body and serialize it
to CBOR. This can be done with cardano-cli
or transaction
builder frameworks.
For example, with cardano-cli
, it can be done as
follows:
cardano-cli conway transaction build-raw [ins, outs and other required args] --out-file tx.draft
The transaction body CBOR can then be obtained from the
tx.draft
file - specifically from the cborHex
JSON field.
cardano-transaction-lib
also provides a straightforward way of building unbalanced transactions
using Contract
, for example:
<- buildTx
unbalancedTx Pay ...
[ ]
The CBOR can then be obtained by calling the encodeCbor
function on unbalancedTx
.
Pisa Fees positions can be queried via the Pisa indexer: wss://indexer-server.pisa-fees.staging.mlabs.city/ws.
The Public WebSocket API provides a list of available queries.
For example, the following query will return all currently active positions, allowing the user to select one with suitable tokens:
{
"requestId": "6fb8473d-807c-40b6-b4ca-478664b96ef4",
"queryType": "getAllPositions",
"payload": null
}
Note that requestId
(UUID) should be generated and
supplied by the caller to match responses with requests during WebSocket
communication.
The response might look like this:
{
"status": "success",
"data": {
"requestId": "6fb8473d-807c-40b6-b4ca-478664b96ef4",
"response": {
"allPositions": [
{
"owner": "a989a5ddd49a85d9d23509037cf5b1d6eacfdf8e3518b52b29c5edc6",
"positionRef": "42085b8b6635404bc2ac13e65c5a5c729deb3fa689c3eb841c28685b25bd67c8#0",
"rates": [
{
"assetClass": "9f30db07c6ae78fe003eee54cac942401a0f0e5fd4eef3b7d5bf9ba0.536f6d65546f6b656e",
"rate": {
"denominator": 10,
"numerator": 1
}
}
]
},
...
]
}
}
}
In the rates
field of the position object, we can see
all assets available for swap in the current position, along with their
exchange rates. The assetClass
field represents
[minting-policy-id].[hex-encoded-token-name]
.
The transaction output reference of the position UTxO from the
positionRef
field will be required to perform balancing
with the Pisa balancer service.
Now, with the transaction CBOR obtained in Step 1 and the position out ref obtained in Step 2, you can execute a balancing request to the Pisa balancer.
A balance request looks like this:
{
"requestId": "6fb8473d-807c-40b6-b4ca-478664b96ef4",
"requestType": "balanceCbor",
"payload": {
"positionRef": "42085b8b6635404bc2ac13e65c5a5c729deb3fa689c3eb841c28685b25bd67c8#0",
"swapAssets": [
"9f30db07c6ae78fe003eee54cac942401a0f0e5fd4eef3b7d5bf9ba0.536f6d65546f6b656e"
],
"unbalancedTxCbor": "[CBOR from step 1]",
"userAddresses": [
"addr_test1..."
],
"userChangeAddress": "addr_test1...",
"userCollateral": null
}
}
Important notes:
payload.unbalancedTxCbor
field contains the CBOR of
the unbalanced transaction obtained in Step 1payload.positionRef
field contains the out ref of
the position obtained in Step 2payload.userAddresses
to select additional inputs to
balance the transaction. The order in which these addresses are used is
not deterministic; therefore, the final transaction will require
signatures from all private keys associated with each addresspayload.userChangeAddress
is where change will be sent.
⚠️ This includes any Ada surplus obtained from the assets exchange
⚠️payload.userCollateral
can be set to null
or a specific UTxO. A value of null
indicates that the
balancer should select appropriate collateral automatically. If a
non-null value representing a specific input UTxO is provided, that UTxO
will be used exclusively as collateral and will be excluded from the set
of UTxOs considered for transaction balancingIn response, the Pisa balancer will return the following JSON:
{
"status": "success",
"data": {
"balancedCbor": "[CBOR hex of balanced transaction]",
"requestId": "6fb8473d-807c-40b6-b4ca-478664b96ef4"
}
}
The CBOR from the balancer response will contain an unsigned balanced transaction body. Typically, transaction builder frameworks provide a way to build a transaction body from CBOR. The parsed body can then be signed and submitted in the way the framework handles it.
A concrete example using cardano-cli
is available in the section
below.
A CTL fork with Pisa integration is available here in the pisa-ws-integration branch.
An example of a Contract
that performs balancing via
Pisa balancer is available in the examples
directory in the
PisaBalance.purs
module. Using this Contract
, users can send tokens to
another address and use the same or other tokens to pay for transaction
fees and the minimum required Ada by performing balancing via the Pisa
Fees backend.
lucid-evolution
A lucid-evolution
fork with Pisa integration is
available here in the
pisa branch.
For examples, see the documentation for the Pisa
object
and completeWithPisa
method.
For Atlas, we provide library-level integration, as Pisa Fees off-chain and backend are powered by Atlas. This means that the Pisa Fees off-chain package can be used directly as a dependency in any Atlas project.
cardano-cli
Below is the set of commands that can be used to build, balance, and
submit a transaction using cardano-cli
and the deployed
Pisa Fees services, step by step (note that assets and addresses will
need to be adjusted for your specific setup):
1. Get wallet UTxO to build draft transaction
cardano-cli query utxo --testnet-magic 1 --socket-path cardano-node.socket --address addr_test1qqa0rdmen6qcyskexlmzm6ljy8qv7xl06k73l34vcceds2luyj98ldkjdkmnketfz5stjmrzehk8mqumegev9r5tu3lsgta7l4
2. Build draft transaction
cardano-cli conway transaction build-raw \
--tx-in [input-from-previous-step] \
--tx-out addr_test1qrp6w67kh762fkt9myhx54u64x2wmlyjr83trhqjlw3z9cpak3rw8tjnlxevmp2qkl0j4zurdkm2gzksxl7kdjef925q6pz0nc+"1 1b650ba85f6590eebebe138cce94d96c62fcc332bbcfb3d9b3a11f33.53656e64546f6b656e4f6e65" \
--fee 0 \
--out-file swap-tx.draft
The CBOR of the unbalanced transaction will be in the
cborHex
field of the JSON in the swap-tx.draft
file.
3. Call Pisa indexer API and pick position for swap
Pisa Indexer: wss://indexer-server.pisa-fees.staging.mlabs.city/ws
{
"requestId": "6fb8473d-807c-40b6-b4ca-478664b96ef4",
"queryType": "getAllPositions",
"payload": null
}
Select a suitable position from the response (the value of the
specific positionRef
will be required for the next
step).
4. Make balancing request to Pisa balancer API
Pisa Balancer: wss://server-ws-api.pisa-fees.staging.mlabs.city/ws
The request will need: - CBOR of the transaction draft from step 2 - Position out ref selected in step 3
Balancing request template:
{
"requestId": "c2cc10e1-57d6-4b6f-9899-38d972112d8c",
"requestType": "balanceCbor",
"payload": {
"positionRef": "TODO: position ref from indexer",
"swapAssets": [
"TODO: asset class for swap"
],
"unbalancedTxCbor": "TODO: cbor of unbalanced transaction]",
"userAddresses": [
"addr_test1qqa0rdmen6qcyskexlmzm6ljy8qv7xl06k73l34vcceds2luyj98ldkjdkmnketfz5stjmrzehk8mqumegev9r5tu3lsgta7l4"
],
"userChangeAddress": "addr_test1qqa0rdmen6qcyskexlmzm6ljy8qv7xl06k73l34vcceds2luyj98ldkjdkmnketfz5stjmrzehk8mqumegev9r5tu3lsgta7l4",
"userCollateral": null
}
}
5. Create transaction envelope file with balanced CBOR
Take the balanced CBOR from the Pisa balancer response
(balancedCbor
field) and create a transaction envelope to
sign with cardano-cli
.
Balancer response example:
{
"status": "success",
"data": {
"balancedCbor": "[cbor hex]",
"requestId": "6fb8473d-807c-40b6-b4ca-478664b96ef4"
}
}
cardano-cli
transaction envelope template:
{
"type": "Unwitnessed Tx ConwayEra",
"description": "Ledger Cddl Format",
"cborHex": "[cbor of balanced transaction]"
}
6. Sign transaction and submit
cardano-cli conway transaction sign --testnet-magic 1 --signing-key-file /TODO/path/to/key.skey --tx-file [envelope file] --out-file [signed-tx-file]
cardano-cli conway transaction submit --testnet-magic 1 --socket-path cardano-node.socket --tx-file [signed-tx-file]
To get the transaction ID:
cardano-cli conway transaction txid --tx-file [signed-tx-file]