-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CAP-0067 draft - Unified Asset Events #1613
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
f25770e
CAP-0064 - Unified Events
sisuresh 10f0e72
Update README
sisuresh b1f12b9
Update core/cap-0065.md
sisuresh e341960
Update
sisuresh 7df5bbb
Rename to CAP-67
sisuresh fb6e5be
Merge remote-tracking branch 'upstream/master' into unified
sisuresh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,304 @@ | ||
## Preamble | ||
|
||
``` | ||
CAP: 0067 | ||
Title: Unified Asset Events | ||
Working Group: | ||
Owner: [email protected] | ||
Authors: Siddharth Suresh <@sisuresh>, Leigh McCulloch <@leighmcculloch> | ||
Consulted: Dmytro Kozhevin <@dmkozh>, Jake Urban <[email protected]>, Simon Chow <[email protected]> | ||
Status: Draft | ||
Created: 2025-01-13 | ||
Discussion: https://github.com/stellar/stellar-protocol/discussions/1553 | ||
Protocol version: 23 | ||
``` | ||
|
||
## Simple Summary | ||
|
||
Emit `transfer`, `mint`, `burn`, `clawback`, `set_authorized`, and `fee` events in Classic in the same format as what we see in Soroban so that the movement of assets can be tracked using a single stream of data. In addition to emitting events in Classic, update the events emitted in the Stellar Asset Contract to be semantically correct and compatible with SEP-41. | ||
|
||
## Motivation | ||
|
||
Tracking the movement of Stellar assets today is complex because you need to consume both Soroban events emitted by the Stellar Asset Contract and ledger entry changes for Classic operations. There are also differences between Stellar assets and custom Soroban tokens that this CAP will address so those differences will be made irrelevant to the end user. | ||
|
||
### Goals Alignment | ||
|
||
This CAP is aligned with the following Stellar Network Goals: | ||
|
||
- The Stellar Network should be secure and reliable, and should bias towards safety, simplicity, | ||
reliability, and performance over new functionality. | ||
|
||
## Abstract | ||
|
||
This CAP specifies three changes - | ||
1. Emit an event for every movement of an `Asset` of types `ASSET_TYPE_NATIVE`, `ASSET_TYPE_CREDIT_ALPHANUM4`, and `ASSET_TYPE_CREDIT_ALPHANUM12`. in Stellar classic. All of the added events will follow the format of the existing Stellar Asset Contract events, with the exception of a new `fee` event to track fees paid by the source account. | ||
2. Remove the admin from the topics of the `mint` and `clawback` events emitted in the SAC. | ||
3. Update issuer semantics in the SAC so that a `transfer` involving the issuer will emit the semantically correct event (`mint` or `burn`). | ||
|
||
The added events will not be a protocol change because they won't be hashed into the ledger, but the Stellar Asset Contract changes will be. | ||
|
||
## Specification | ||
|
||
### XDR Changes | ||
|
||
This patch of XDR changes is based on the XDR files in commit `734bcccdbb6d1f7e794793ad3b8be51f3ba76f92` of stellar-xdr. | ||
``` | ||
diff --git a/Stellar-contract.x b/Stellar-contract.x | ||
index 5113005..ee10e20 100644 | ||
--- a/Stellar-contract.x | ||
+++ b/Stellar-contract.x | ||
@@ -179,7 +179,9 @@ case CONTRACT_EXECUTABLE_STELLAR_ASSET: | ||
enum SCAddressType | ||
{ | ||
SC_ADDRESS_TYPE_ACCOUNT = 0, | ||
- SC_ADDRESS_TYPE_CONTRACT = 1 | ||
+ SC_ADDRESS_TYPE_CONTRACT = 1, | ||
+ SC_ADDRESS_TYPE_CLAIMABLE_BALANCE = 2, | ||
+ SC_ADDRESS_TYPE_LIQUIDITY_POOL = 3 | ||
}; | ||
|
||
union SCAddress switch (SCAddressType type) | ||
@@ -188,6 +190,10 @@ case SC_ADDRESS_TYPE_ACCOUNT: | ||
AccountID accountId; | ||
case SC_ADDRESS_TYPE_CONTRACT: | ||
Hash contractId; | ||
+case SC_ADDRESS_TYPE_CLAIMABLE_BALANCE: | ||
+ ClaimableBalanceID claimableBalanceID; | ||
+case SC_ADDRESS_TYPE_LIQUIDITY_POOL: | ||
+ PoolID liquidityPoolID; | ||
}; | ||
|
||
%struct SCVal; | ||
``` | ||
|
||
## Semantics | ||
|
||
### Remove the admin from the SAC `mint` and `clawback` events | ||
|
||
The `mint` event will look like: | ||
``` | ||
contract: asset, topics: ["mint", to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
The `clawback` event will look like: | ||
``` | ||
contract: asset, topics: ["clawback", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
### Emit the semantically correct event for a Stellar Asset Contract `transfer` when the issuer is involved | ||
|
||
At the moment, if the issuer is the sender in a Stellar Asset Contract `transfer`, the asset will be minted. If the issuer is the recipient, the asset will be burned. The event emitted in both scenarios, however, is the `transfer` event. This CAP changes that behavior to instead emit the `mint`/`burn` event. | ||
|
||
### New Events | ||
This section will go over the semantics of how the additional `transfer` events are emitted for each operation, as well as the `fee` event emitted for the fee paid by the source account. These events will be emitted through `TransactionMeta`, and will not be hashed into the ledger. Note that | ||
the `contract` field for these events corresponds to the Stellar Asset Contract address for the respective asset. Note that the Stellar Asset Contract instance is not required to be deployed for the asset. The events will be published using the reserved contract address regardless of deployment status. | ||
|
||
#### Fees paid by source account | ||
|
||
For each transaction whose source account pays fees for the execution of a transaction, emit an event in the following format: | ||
``` | ||
contract: native asset, topics: ["fee", from:Address], data: [amount:i128] | ||
``` | ||
Where from is the account paying the fee, either the fee bump fee account or the tx source account. | ||
|
||
#### Payment | ||
Emit one of the following events - | ||
|
||
For a payment not involving the issuer, or if both the sender and receiver are the issuer: | ||
``` | ||
contract: asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
When sending from an issuer: | ||
``` | ||
contract: asset, topics: ["mint", to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
When sending to an issuer: | ||
``` | ||
contract: asset, topics: ["burn", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Path Payment Strict Send / Path Payment Strict Receive | ||
For each movement of the asset created by the path payment, emit one of the following - | ||
|
||
For a movement not involving the issuer: | ||
``` | ||
contract: asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
When sending from an issuer: | ||
``` | ||
contract: asset, topics: ["mint", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
When sending to an issuer: | ||
``` | ||
contract: asset, topics: ["burn", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Create Account | ||
Emit the following event: | ||
``` | ||
contract: native asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* `from` is the account being debited (creator). | ||
* `to` is the account being credited (created). | ||
* `amount` is the starting native balance. | ||
|
||
#### Merge Account | ||
Emit the following event: | ||
``` | ||
contract: native asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* `from` is the account being debited (merged). | ||
* `to` is the account being credited (merged into). | ||
* `amount` is the merged native balance. | ||
|
||
#### Create Claimable Balance | ||
Emit the following event: | ||
``` | ||
contract: asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* from is the account being debited. | ||
* to is the claimable balance being created. The type of this address will be `SC_ADDRESS_TYPE_CLAIMABLE_BALANCE`. | ||
* amount is the amount moved into the claimable balance. | ||
|
||
If an asset is a movement from the issuer of the asset, instead emit for the movement: | ||
``` | ||
contract: asset, topics: ["mint", to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Claim Claimable Balance | ||
Emit the following event: | ||
``` | ||
contract: asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
* `from` is the claimable balance. The type of this address will be `SC_ADDRESS_TYPE_CLAIMABLE_BALANCE`. | ||
* `to` is the account being credited | ||
* `amount` is the amount in the claimable balance | ||
|
||
If the claim is a movement to the issuer of the asset, instead emit for the movement: | ||
``` | ||
contract: asset, topics: ["burn", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Liquidity Pool Deposit | ||
Emit the following events: | ||
``` | ||
contract: assetA, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
contract: assetB, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* `from` is the account being debited. | ||
* `to` is the liquidity pool being credited. The type of this address will be `SC_ADDRESS_TYPE_LIQUIDITY_POOL`. | ||
* `amount` is the amount moved into the liquidity pool. | ||
|
||
If an asset is a movement from the issuer of the asset, instead emit for the movement: | ||
``` | ||
contract: asset, topics: ["mint", to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Liquidity Pool Withdraw | ||
Emit the following events: | ||
``` | ||
contract: assetA, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
contract: assetB, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* `from` is the liquidity pool. The type of this address will be `SC_ADDRESS_TYPE_LIQUIDITY_POOL`. | ||
* `to` is the account being credited. | ||
* `amount` is the amount moved out of the liquidity pool. | ||
|
||
|
||
If an asset is issued by the withdrawer, instead emit for the movement of the issued asset: | ||
``` | ||
contract: asset, topics: ["burn", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Manage Buy Offer / Manage Sell Offer / Create Passive Sell Offer | ||
Emit two events per offer traded against. Each pair of events represents both sides of a trade. This does mean zero events can be emitted if the resulting offer is not marketable - | ||
|
||
``` | ||
contract: assetA, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
contract: assetB, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
If an asset is a movement from the issuer of the asset, instead emit for that movement: | ||
``` | ||
contract: asset, topics: ["mint", to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
If an asset is a movement to the issuer of the asset, instead emit for the movement: | ||
``` | ||
contract: asset, topics: ["burn", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
#### Clawback / Clawback Claimable Balance | ||
Emit the following event: | ||
|
||
``` | ||
contract: asset, topics: ["clawback", from:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* `from` is the account or claimable balance being credited. | ||
* `amount` is the amount being moved out of the account and burned. | ||
|
||
|
||
#### Allow Trust / Set Trustline Flags | ||
If either operation is used to revoke authorization from a trustline that deposited into a liquidity pool then claimable balances will be created for the withdrawn assets (See [CAP-0038](cap-0038.md#SetTrustLineFlagsOp-and-AllowTrustOp) for more info). If any claimable balances are created due to this scenario, emit the following event: | ||
|
||
``` | ||
contract: asset, topics: ["transfer", from:Address, to:Address, sep0011_asset:String], data: amount:i128 | ||
``` | ||
|
||
* `from` is the liquidity pool. The type of this address will be `SC_ADDRESS_TYPE_LIQUIDITY_POOL`. | ||
* `to` is the claimable balance being created. The type of this address will be `SC_ADDRESS_TYPE_CLAIMABLE_BALANCE`. | ||
* `amount` is the amount moved into the claimable balance. | ||
|
||
## Design Rationale | ||
|
||
### Remove the admin from the SAC `mint` and `clawback` events | ||
|
||
The admin isn't relevant information when a mint or `clawback` occurs, and it hinders compatibility with SEP-41 for when these two events are added to it because the admin is an implementation detail. For a custom token, an admin doesn't need to be a single `Address`, or an admin may not required at all to emit either event. | ||
|
||
### No change to TransactionMeta XDR | ||
|
||
By using the existing `events<>` vector in `SorobanTransactionMeta`. We can avoid making any xdr changes. This does have some tradeoffs, mainly that | ||
1. All events for a given transaction will be emitted in a single vector, making it impossible to distinguish which operation emitted a specific event. The alternative would be to move Soroban meta from the transaction layer into the operation layer of transaction meta, but that would be a breaking change. | ||
2. Soroban events are hashed into the return value of `InvokeHostFunctionResult` which allows you to cryptographically verify the `events<>` vector. Using the same `events<>` vector may cause some confusion because the Classic events won't be hashed into anything. | ||
|
||
### Emit the semantically correct event instead of no longer allowing the issuer to transfer due to missing a trustline | ||
|
||
The Stellar Asset Contract special cases the issuer logic because issuers can't hold a trustline for their own assets. This matches the logic in Classic. The special case was unnecessary however because the Stellar Asset Contract provides the `mint` and `burn` functions. This CAP could instead just remove the special case and allow `transfers` involving the issuer to fail due to a missing trustline, | ||
but this would break any contracts that rely on this behavior (it's not known at this time if contracts like this exist, but we could check if there are any `transfers` on pubnet that involve the issuer). That's why this CAP chooses to instead emit the correct event in this scenario. | ||
|
||
### New SCAddressType types | ||
|
||
This CAP adds two new `SCAddressType` types - `SC_ADDRESS_TYPE_CLAIMABLE_BALANCE` and `SC_ADDRESS_TYPE_LIQUIDITY_POOL`. These types are used in the topic of an event where the address is not a contract or a stellar account. | ||
|
||
## Protocol Upgrade Transition | ||
On the protocol upgrade, the SAC will start emitting the `mint` and `clawback` events without the `admin` topic. Also, the `transfer` event will not be emitted for `transfers` involving the issuer. Instead, the appropriate `mint`/`burn` will be emitted. | ||
|
||
The unified events will not be part of the protocol, so they can be enabled with a configuration flag at anytime. | ||
|
||
### Backwards Incompatibilities | ||
|
||
|
||
### Resource Utilization | ||
The additional events will use more resources if a node chooses to emit them. | ||
|
||
|
||
## Security Concerns | ||
|
||
|
||
## Future work | ||
|
||
|
||
## Test Cases | ||
|
||
|
||
## Implementation |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs clarity on who
from
andto
are, hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll address this in a follow up