Signing Transactions from third party dApps¶
A normal flow on blockchain applications is to have dApps that interact with the blockchain on the clients behalf, these flows usually require the user to sign transactions that the dApp prepares and submit it. To faciliate this in Canton it is required that the prepared transaction is sent to the wallet for signing. An easy way of supporting this is to expose a dApp API (OpenRPC spec can be found here: https://github.com/hyperledger-labs/splice-wallet-kernel/blob/main/api-specs/openrpc-dapp-api.json ).
The specs are in OpenRPC to conform with traditional standards like for ethereum.
A client can provide access to a Wallet Providers dApp API by either embedding a wallet provider in the dApp or by connecting to an external wallet provider via a browser extension or other means. Then the dApp is able to funnel transactions through to the wallet provider for signing.
Receiving a Transaction¶
A dApp would usually call the prepareReturn
endpoint or the prepareExecute
endpoint. In both cases the Wallet Provider
would prepare and sign the transaction (but for the prepareExecute
it would also submit it to the ledger).
You can prepare the incoming transaction using the Wallet SDK:
import {
WalletSDKImpl,
localNetAuthDefault,
localNetLedgerDefault,
signTransactionHash,
TopologyController,
} from '@canton-network/wallet-sdk'
import { v4 } from 'uuid'
const sdk = new WalletSDKImpl().configure({
logger: console,
authFactory: localNetAuthDefault,
ledgerFactory: localNetLedgerDefault,
})
const prepareExecuteParams = {
commands: {}, // this is of type JsCommand
}
const preparedTransaction = await sdk.userLedger?.prepareSubmission(
prepareExecuteParams.commands, //the incoming command
v4() //a unique deduplication id for this transaction
)
const clientsPublicKey = 'clients-public-key-here'
const clientsPrivateKey = 'client-private-key-here'
const signature = signTransactionHash(
preparedTransaction?.preparedTransactionHash ?? '',
clientsPrivateKey
)
//if client calls ``prepareExecute`` then this is how they would call ``execute``
await sdk.userLedger?.executeSubmission(
preparedTransaction!,
signature,
clientsPublicKey,
v4()
)
Reading and Visualising the Transaction¶
It is important when integrating with third party dApps to showcase the User exactly what is being signed. Once the signature is applied the transaction can be considered valid (and executed). The easiest would be to create a visualizer that takes a JSON representation of the transaction. The Json for a prepared transaction (before signature is applied) can be obtained using the Wallet SDK:
import {
WalletSDKImpl,
localNetAuthDefault,
localNetLedgerDefault,
decodePreparedTransaction,
PreparedTransaction,
} from '@canton-network/wallet-sdk'
import { v4 } from 'uuid'
const sdk = new WalletSDKImpl().configure({
logger: console,
authFactory: localNetAuthDefault,
ledgerFactory: localNetLedgerDefault,
})
const prepareExecuteParams = {
commands: {}, // this is of type JsCommand
}
const preparedTransaction = await sdk.userLedger?.prepareSubmission(
prepareExecuteParams.commands, //the incoming command
v4() //a unique deduplication id for this transaction
)
const decodedTransaction = decodePreparedTransaction(
preparedTransaction!.preparedTransaction!
)
const JsonTransaction = PreparedTransaction.toJson(decodedTransaction)
// Here you can use your choice of JSON visualizer