- RFC-Number: 011
- Status: Draft
- Created on: 27 Mar. 2019
Table of Contents
This RFC describes to execute a RFC003 SWAP where one of the ledgers is Bitcoin and the associated asset is an Omni Layer token asset.
For the definition of the Bitcoin ledger see RFC004. For the definition of the Omni Layer token asset see RFC010.
This RFC re-purposes the Hash Time Locked Contract (HTLC) Bitcoin script from RFC005 to lock Omni Layer tokens instead of Bitcoin.
To fulfil the requirements of RFC003 this RFC defines:
- How to construct Omni layer transactions transferring Omni Layer tokens to a HTLC address
- How to deploy, redeem and refund the HTLC during the execution phase of RFC003
This sections describes how to build Omni Layer transactions for the purpose of a RFC003 SWAP. Note that Omni Layer uses an account based model layered on top of Bitcoin's UTXO model. For a further description of this see RFC-010.
This RFC uses the simple send Omni Layer transaction type, encoded using the Class C format.
Class C transactions use Bitcoin OP_RETURN
instruction to store the Omni Layer data on-chain.
The OP_RETURN
data MAY be constructed manually according to the Simple Send Transfer Coins section of the Omni Layer spec.
For reference, here are links to the parts of the Omnicore implementation that produce the OP_RETURN
data:
Alternatively, the implementer MAY decide to rely on an existing Omni Layer implementation to generate it.
For example, the omni_createpayload_simplesend
RPC api call can be used to produce the OP_RETURN
data given the following:
property_id
: the property id of the Omni Layer Asset (e.g.31
for TetherUS)amount
: the quantity of Omni Layer Assets to transfer (e.g.20
)
The 16 bytes produced by the call MUST then be prefixed with the 4-byte Omni Layer header, 6f6d6e69
, and included in the correct OP_RETURN
output.
Bitcoin Core has limitations on minimum amounts owned by a UTXO. The minimum value is 546 satoshis for a normal transaction and 294 satoshis for SegWit transactions. See RFC-010 for details.
The values above will be referred as min_sat
from now on.
OP_RETURN
outputs are not spendable and hence SHOULD not be assigned any Bitcoin value.
Only spendable outputs MUST have at least min_sat
Satoshis assigned.
The HTLC address MUST either be:
- The P2WSH address of the HTLC, as described in RFC-005
- or the P2SH of the P2WSH above, as descriped in BIP-0141 Segregated Witness
(1) is preferred. However, not all Omni Layer wallets implementation support bech32 addresses so (2) can be used as a fallback.
The simple send MUST NOT be done to the old-style P2SH address of the HTLC.
This choice has been made to:
- Limit the number of addresses to watch, making implementation less cumbersome.
- Avoid defining the basic HTLC twice (once, in P2SH format, once in P2WSH format).
- Follow the common strategy for segwit backward compatibility (nesting in P2SH).
This section describes specific inputs & outputs to construct an Omni Layer transaction for redeeming and refunding the HTLC output.
To construct a transaction to spend from the HTLC, the following information is needed:
Variable | Description |
---|---|
htlc_utxo |
UTXO locked by the HTLC, created with the deployment transaction |
to_address |
Address to which the Omni Layer token is sent out of the HTLC |
change_address |
Address to which the Bitcoin change will be sent upon redeeming; MUST be different than to_address |
change_utxo |
UTXO locked by change_address that owns some Bitcoin asset to pay for the mining fee |
init_change_sat |
Amount of Satoshis owned by change_utxo before the redeem |
mining_sat |
The amount of Satoshi to be spent on mining fees |
omni_data |
The Omni Layer data that transfers the Omni Layer Asset as described in Omni Layer data |
The Bitcoin transaction MUST be constructed with the following inputs, outputs and values. The assigned Bitcoin value on the inputs SHOULD be as described.
Inputs (assigned Bitcoin value) | Outputs (assigned Bitcoin value) |
---|---|
1. htlc_utxo (min_sat ) |
1. to_address (min_sat ) |
2. change_utxo (init_change_sat ) |
2. change_address (init_change_sat - mining_sat ) |
3. OP_RETURN omni_data (0 ) |
The implementor MAY include output (2) change_address
or MAY decide to omit it and transfer the Bitcoin change to to_address
.
If output (2) change_address
is present then input (2) change_utxo
MUST be included to ensure the Omni Layer Assets are sent to output (1) to_address
.
In any case, it is unlikely the transaction will have enough fees to be included if change_utxo
is not present.
The following section describes how both parties should interact with the Bitcoin blockchain during the RFC003 execution phase.
At the start of the deployment stage, both parties compile the contract script as described in RFC-005.
We will call this value contract_script
.
To deploy the Bitcoin HTLC, the funder must confirm a simple send Omni Layer transaction transferring the Omni Layer tokens to the HTLC address derived from contract_script
on the relevant Bitcoin blockchain.
The transaction MUST have the following properties:
- It MUST be a
valid
Omni Layer transaction. - It MUST be simple send Omni Layer transaction Class C.
- The simple send
amount
MUST be equal to thequantity
parameter in the Omni Layer asset header. - It MUST have an output with a
scriptPubKey
in the form of:- a Pay-To-Witness-Script-Hash (P2WSH) derived from
contract_script
(See BIP141 for how to construct thescriptPubkey
from thecontract_script
). - OR a Pay-To-Witness-Script-Hash nested in Pay-To-Script-Hash (P2WSH(P2SH)) derived from
contract_script
(See BIP141 for how to construct thescriptPubkey
from thecontract_script
).
- a Pay-To-Witness-Script-Hash (P2WSH) derived from
To be notified of the deployment event, both parties MAY watch the blockchain for a transaction with the above properties.
To validate the transaction, implementations MAY use the omni_gettransaction
omnicore API call with the transaction id.
This will return a structure like:
{
"txid": "72abc494e877d7e2491ffa6fea3694648aa75e6166e42d6381b04d41ca933fb5",
"fee": "0.00003046",
"sendingaddress": "mxuetdW3Yq8KEsvB4L37Z5jmMQMTxZF9Be",
"referenceaddress": "2N4CHfBpitHNXj9nBcJCFs7BXUaoNVTegBZ",
"ismine": false,
"version": 0,
"type_int": 0,
"type": "Simple Send",
"propertyid": 2147483652,
"divisible": false,
"amount": "5300",
"valid": true,
"blockhash": "6e9976c5d6c2b4be2928972c93564a0fc0ccdabe4ac581378fad65753559d0b0",
"blocktime": 1556091362,
"positioninblock": 1,
"block": 441,
"confirmations": 6
}
From it, implementations MUST validate the following:
referenceaddress
: MUST be the HTLC address (e.g.2N4CHfBpitHNXj9nBcJCFs7BXUaoNVTegBZ
)valid
: MUST betrue
amount
: MUST be negotiated the quantity of asset (e.g.5300
)
To redeem the HTLC, the redeemer MUST submit a valid Omni Layer transaction transferring all the omni tokens from the HTLC address to their desired address using simple send. The transaction should be constructed according to the Constructing an Omni Layer Transaction section. To construct the witness data for the P2WSH output, the redeemer MUST use the procedure described in the Redeem section of RFC005.
To be notified of the redeem event, both parties MAY watch the blockchain for transactions that spend from the output and check that the witness data is in the form specified in the Redeem section of RFC005.
Note that The witness for the htlc_utxo
input will contain the secret if it is able to spend from it even if the transaction is not a valid Omni Layer transaction.
To refund the HTLC, the funder MUST submit a valid Omni Layer transaction transferring all the omni tokens from the HTLC address to their desired address using simple send. The transaction should be constructed according to the Constructing an Omni Layer Transaction section. To construct the witness data for the P2WSH output, the funder MUST use the procedure described in the Refund section of RFC005.
To be notified of the refund event, both parties MAY watch the blockchain for a transactions that spends from the output and check that the witness data is in form specified in the Refund section of RFC005.
The following shows an RFC003 SWAP REQUEST where the alpha_ledger
is Bitcoin, the alpha_asset
is 1 Omni Layer Asset TetherUS (with ...
being used where the value is only relevant for the beta_ledger
).
{
"type": "SWAP",
"headers": {
"alpha_ledger": {
"value": "bitcoin",
"parameters": { "network": "mainnet" }
},
"beta_ledger": {...},
"alpha_asset": {
"value": "omni",
"parameters": {
"quantity": "100000000",
"property_id": 31,
}
},
"beta_asset": {...},
"protocol": {
"value" : "comit-rfc-003",
"parameters" : { "hash_function" : "SHA-256" }
}
},
"body": {
"alpha_ledger_refund_identity": "1925a274ac004373bb5429553bdb55c40e57b124",
"alpha_expiry": 1552263040,
"secret_hash" : "1f69c8745f712da03fdd43486ef705fc24f3e34d54cf44d967cf5cd4204c835e",
"beta_ledger_redeem_identity" : "...",
"beta_expiry" : ...
},
}
Note, the property id of TetherUS is 31
and TetherUS is divisible;
the secret for the secret_hash
is 51a488e06e9c69c555b8ad5e2c4629bb3135b96accd1f23451af75e06d3aee9c
.
A valid RESPONSE
to the above REQUEST
could look like:
{
"status" : "OK00",
"body": {
"alpha_ledger_redeem_identity": "c021f17be99c6adfbcba5d38ee0d292c0399d2f5",
"beta_ledger_refund_identity": "..."
}
}
The above REQUEST
and RESPONSE
results in the following parameters to the HTLC:
Parameter | value |
---|---|
redeem_identity | c021f17be99c6adfbcba5d38ee0d292c0399d2f5 |
refund_identity | 1925a274ac004373bb5429553bdb55c40e57b124 |
secret_hash | 1f69c8745f712da03fdd43486ef705fc24f3e34d54cf44d967cf5cd4204c835e |
expiry | 1552263040 |
Which compiles into the following Bitcoin script bytes:
6382012088a8201f69c8745f712da03fdd43486ef705fc24f3e34d54cf44d967cf5cd4204c835e8876a914c021f17be99c6adfbcba5d38ee0d292c0399d2f5670480a7855cb17576a9141925a274ac004373bb5429553bdb55c40e57b1246888ac
Which results in the following P2WSH address by network:
Network | Address |
---|---|
regtest |
bcrt1q4vft3swvhm5zvytlsx0puwsge7pnsj4zmvwp9gcyvwhnuthn90ws9hj4q3 |
testnet |
tb1q4vft3swvhm5zvytlsx0puwsge7pnsj4zmvwp9gcyvwhnuthn90wsgwcn4t |
mainnet |
bc1q4vft3swvhm5zvytlsx0puwsge7pnsj4zmvwp9gcyvwhnuthn90wslxwu0y |
and the following P2SH(P2WSH) address by network:
Network | Address |
---|---|
regtest |
2NEzrgyqU2AB6tHZqeCNnkmHKEDRGpGkDfk |
testnet |
2NEzrgyqU2AB6tHZqeCNnkmHKEDRGpGkDfk |
mainnet |
3PSedEuSQhfkgVwHy4kv8pJ41sD6wE8Hc5 |