I propose that we extend the predicates available to Claimable Balances, adding a new predicate CLAIM_PREDICATE_SIGNER_HASH_X that requires that a ClaimClaimableBalanceOp be accompanied by a SIGNER_KEY_TYPE_HASH_X signature containing x.
diff --git a/src/xdr/Stellar-ledger-entries.x b/src/xdr/Stellar-ledger-entries.x
index 8d746391..7b09302f 100644
@@ -291,7 +291,8 @@ enum ClaimPredicateType
CLAIM_PREDICATE_OR = 2,
CLAIM_PREDICATE_NOT = 3,
CLAIM_PREDICATE_BEFORE_ABSOLUTE_TIME = 4,
- CLAIM_PREDICATE_BEFORE_RELATIVE_TIME = 5
+ CLAIM_PREDICATE_BEFORE_RELATIVE_TIME = 5,
+ CLAIM_PREDICATE_SIGNATURE_HASH_X = 6
union ClaimPredicate switch (ClaimPredicateType type)
@@ -309,6 +310,8 @@ case CLAIM_PREDICATE_BEFORE_ABSOLUTE_TIME:
int64 relBefore; // Seconds since closeTime of the ledger in which the
// ClaimableBalanceEntry was created
+ uint256 hashX; // Hash of random 256 bit preimage X
This would function similar to how the account hash(x)
account signer works:
First, create a random 256 bit value, which we call x. The SHA256 hash of that value can be added as a predicate of type hash(x). Then in order to authorize a claim, the claimant must include x as one of the signatures of the transaction. X will only be usable by the claimant that it is included as a predicate, so exposure of x does not allow any individual to issue a claim if the transaction was to fail and the claimant needed to reissue the claim. Transactions do not need to be created upfront for the claims, they can be constructed after the fact and take any form.
Account AA wishes to send Asset A1 to Account AB on Stellar. Account AB wishes to send Asset A2 to Account AA on OtherChain. Both accounts do not trust each other and the swap needs to occur such that once either party can take the other's asset, both can.
1. Account AA randomly generates a value for x
2. Account AA submits transaction CreateClaimableBalanceOp: SourceAccount: AA, Asset: A1, Amount: 1, Claimants: [AA with predicate: not before 2 days from now, AB with predicate: hash(x)]
3. Account AB performs a similar operation on OtherChain with asset A2 with timeout 1 day using hash(x)
4. Account AA claims asset on OtherChain using x, revealing x
5. Account AB claims the asset on Stellar with ClaimClaimableBalanceOp: SourceAccount: AB, ClaimableBalanceID: id, Signature: [AB signers, x]
Stellar already supports atomic swaps with time bound pre-authorized transactions and temporary accounts that are locked and therefore have a predefined set of outcomes. One of the pre-authorized transactions also requires the x signature to lock its use to the revealing of x. Using this approach is complex. The author of the transactions must ensure that the pre-authorized transactions won’t fail, or prepare duplicate sets of the transactions for retries. The author is also required to create a temporary account and handle the recovery of minimum account reserves and the creation and destruction of trustlines in these transactions.
1. Account AA randomly generates a value for x
2. Account AA generates a temporary account address AT and key
3. Account AA creates account AT depositing sufficient account reserves for 1 trustline, 3 signers
4. Account AA creates trustline on AT for A1
5. Account AA gets next sequence number SN for AT
6. Account AA creates TX1 (SN+1) “pay A1 to AB, remove trustline for A1, remove TX2 pre-authorized signer, account merge to AA”
7. Account AA creates TX2 (SN+1) “pay A1 to AA, remove trustline for A1, remove TX1 pre-authorized signer, remove hash(x) signer, account merge to AA, timebound to 2 days from now”
8. Account AA submits a SetOptionsOp (SN+0) for AT “remove master key signer, set thresholds to low:2 med:2 high:2, add pre-authorized signer for TX1 weight:1, add hash(x) signer weight:1, add pre-authorized signer for TX2 weight:2.
9. Account AB performs a similar operation on OtherChain with asset A2 with timeout 1 day using hash(x)
10. Account AA claims asset on OtherChain using x, revealing x.
11. Account AB claims the asset on Stellar by adding the x signature to TX2, wrapping the transaction in a fee bump transaction to supply the transaction fee, and submitting it to the network.
It is significantly more complicated to create the pre-authorized transactions and ensure they will not fail. Decisions must be made about how to handle the account reserve and where to send it. If the account reserve is intended to be returned to the sending account the second transaction can fail locking up the asset indefinitely unless the author has prepared retry pre-authorized transactions. There are different approaches for how to handle this like leaving the reserve in the locked account, or sending it to the destination.
These issues, especially the issues relating to the management of the temporary account, are similar to the issues anchors experience sending assets to accounts that do not yet hold trustlines. Claimable balances were introduced to make it simpler for anchors to issue assets to new accounts in protocol 15 and this small predicate extension brings similar wins to atomic swaps as well.
I think this would simplify atomic swaps on Stellar. Are there approaches simpler than what I outline as currently possible without this change? Thoughts?
I’d be happy to write up a formal proposal in the near future if this is of interest.