Description
Summary
The idea is that the wallet-lib will be responsible for querying the wallet-service for utxos and compose the transaction locally before sending it again to the wallet-service to lock the utxos using the txProposalCreate
lambda function.
To be able to do this, we need to develop an API to properly filter the utxos on the wallet-service database.
We also need to refactor the txProposalCreate
API to accept a txHex instead of a partial transaction body (with inputs and outputs).
This is currently implemented in HathorNetwork/hathor-wallet-service#82
Motivation
The motivation for this new token actions format is to make the API more generic to be able to, in the future, handle multi-sig transactions and have "draft" transactions that will be updated by multiple users before being sent.
Guide-level explanation
This implementation will consist of two parts, an API with multiple filters to query UTXOs and a refactor on the txProposalCreate
to accept a txHex
with a full transaction instead of a partial transaction body with only outputs or partial inputs.
The order of a tx creation request will be:
- The wallet-lib will query the wallet-service for UTXOs matching the user needs
- The wallet-lib will assemble a transaction and send it serialized in a
txHex
- The wallet service will decode de-serialize the transaction and validate its contents
- The wallet service will lock the transaction inputs and store a new
txProposal
on the database - The wallet-lib will call the
txProposalSend
function to send the storedtxProposal
using its UUID - The wallet-service will validate if the transaction is the same as the one sent in
txProposalCreate
and push it to the full-node
In step 3, these are the validations we are doing on txProposalCreate
:
- Too many outputs
- Too many inputs
- User not authenticated
- Wallet not ready
- Wallet not found
- Utxos not found
- Utxos not in the user's wallet
- Utxos already used in another tx proposal
Reference-level explanation
Filter Utxos API
GET /utxos
Possible query parameters:
{
addresses: Joi.array()
.items(Joi.string().alphanum())
.min(1)
.required(),
tokenId: Joi.string().default('00'),
authority: Joi.number().default(0).integer().positive(),
ignoreLocked: Joi.boolean().optional(),
biggerThan: Joi.number().integer().positive(),
smallerThan: Joi.number().integer().positive(),
maxUtxos: Joi.number().integer().positive().default(constants.MAX_OUTPUTS),
}
Description:
maxUtxos
: The max number of utxos returned by this API, ordering by the largest utxos first
token
: Filter this token's utxos
addresses
: List of addresses to query utxos
smallerThan
: Utxos must be smaller than the value
biggerThan
: Utxos must be bigger than the value
authority
: Authority byte representing a mask to search on the database, i.e.: 0x01 = Mint, 0x02 = Melt, 0x03 = Mint and Melt
ignoreLocked
: Only utxos that are not time or height locked.
txId
: Filter a single utxo by its txId (and index)
index
: Required if txId
is sent, filter by this txId index
Note: If txId
and index
are sent, only the requested utxo will be returned on the API.
TxProposalCreate API
The API will parse the sent txHex
and do the following validations:
- Validate if the number of outputs <
MAX_OUTPUTS
- Validate if the number of inputs <
MAX_OUTPUTS
- Validate if the wallet is ready
- Validate if the wallet is found
- Validate if the selected utxos are on our database
- Validate if the selected utxos belong to the logged in the wallet
POST /txproposals
{
"id": "23b44673413f093180ed37ce34b6577d7dedbdec9c1d909fe42be1b0bc341ec9",
"txHex": "000101010200034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295d00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e0000694630440220317cd233801c1986c2de900bf8d344c6335d3c385e69d19d65e1fae7a0afd0af02207acddb824debf855798d79c45701cbe3a19aea00baad94bff5290c6f0b0acf8e210346cddff43dffab8e13398633ab7a7caf0d634551e89ae6fd563e282f6744b983000003e800001976a91419a8eb751eab5a13027e8cae215f6a5dafc1a8dd88ac000003e800001f045c66ef4b6f76a914c2f29cfdb73822200a07ab51d261b425af811fed88ac403209eb93c8c29e5c66ef520000000000",
}
TxProposalSend API
The send API expects a txHex
with all inputs already signed.
The txHex
will be parsed and the inputs will be validated. If the same utxos as the txProposalCreate
request were sent, the transaction will be pushed to the full-node
PUT /txproposals/{txProposalId}
{
"txHex": "000101010200034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295d00034a15973117852c45520af9e4296c68adb9d39dc99a0342e23cd6686b295e0000694630440220317cd233801c1986c2de900bf8d344c6335d3c385e69d19d65e1fae7a0afd0af02207acddb824debf855798d79c45701cbe3a19aea00baad94bff5290c6f0b0acf8e210346cddff43dffab8e13398633ab7a7caf0d634551e89ae6fd563e282f6744b983000003e800001976a91419a8eb751eab5a13027e8cae215f6a5dafc1a8dd88ac000003e800001f045c66ef4b6f76a914c2f29cfdb73822200a07ab51d261b425af811fed88ac403209eb93c8c29e5c66ef520000000000",
}
Rationale and alternatives
This design replaces the implementation at HathorNetwork/hathor-wallet-service#61, which was a more strict version of the txProposalCreate
lambda function, allowing only for well defined token actions, like mint, melt, delegate mint, delegate melt, etc...
Future possibilities
It is important to notice that we are currently only locking utxos that belong to the user's wallet. We can easily support multi-sig transactions if we allow for the service to accept utxos from different wallets but that will only lock the ones from the wallet that is calling it.
Also, aside from a few checks described in the Guide-Level explanation, we are not being strict on what types of transactions we are accepting, so this more generic model will allow for more types of transactions that are yet to come, like nano contracts or NFT transactions.