diff --git a/ARCs/arc-0084.md b/ARCs/arc-0084.md new file mode 100644 index 000000000..9ea0fb80a --- /dev/null +++ b/ARCs/arc-0084.md @@ -0,0 +1,750 @@ +--- +arc: 84 +title: ASA-Compatible Smart Contract Tokens +description: A standard for smart contract tokens that are programable but also ASA-compatible +author: Joe Polny (@joe-p) +discussions-to: +status: Draft +type: Standards Track +category: ARC +subcategory: Application +created: 2025=05-27 +requires: 4, 22 +--- + +## Abstract +Abstract is a multi-sentence (short paragraph) technical summary. This should be a very terse and human-readable version of the specification section. Someone should be able to read only the abstract to get the gist of what this specification does. + +## Motivation + +Algorand Standard Assets (ASAs) offer trusted accounting enforced by the protocol and stable endpoints for transferring assets and reading data via APIs. ASAs, however, do not offer flexibility. Programmability is desirable for various asset-related functionalities such as enforced fees, automatic royalties, balance snapshots, and conditional transfers. There are also some additional challenges and limitations with ASAs, including: + +* Developer and user friction with ASA opt-ins +* Immutable metadata fields (and hacky workarounds like ARC-19) +* Metadata standards (i.e. ARC-3) use off-chain mechanisms, which make metadata inaccessible in smart contracts + +As such, there have been various smart-contract-based token standards but they typically have one or more of the following shortcomings: + +* Incompatibility with ASAs (i.e using `uint256` instead of `uint64`) +* Inability to trust accounting logic (without pre-approved programs, which then limit programmability) +* Lack of existing API compatibility +* Difficulty with indexing token balances and transactions + +### Use Cases + +Below are use cases that require at least _some_ asset programmability that may be solved with ARC-84 or more generally any smart contract token standard. This section includes use cases that may be covered by other smart contract token standards. The rationale for why ARC-84 is preferable over these standards is laid out in the other sections throughout this ARC. + +#### Delegation + +The following use cases all have to do with delegation in one form or another. Most of these cases are possible with either a delegated logic sig or sending assets to an escrow contract. + +Delegated logic sigs are discouraged from use for the following reasons: + +* No native way to revoke except for rekeying +* If you do rekey, that undoes all lsig delegations +* Impossible to know what lsigs have been signed +* Lsigs themselves are fundamentally harder to write safely than stateful apps +* Not composable (cannot be used in inner transactions) + +Escrows are not ideal because they inherently expose assets to smart contract risk and require users to reduce asset liquidity. This also makes accounting of ones portfolio harder when assets that are still technically in custody of the user are split across many addresses for escrow purposes. + +##### Subscriptions + +Someone that holds a token such as USDC might want to pay a monthly fee to some on-chain application. Subscriptions are a very common payment model and it would be nice to replicate it on-chain. + +##### Asset Offers & Listings + +One might want to list an NFT for sale but not remove it from their own address. Similarity, they might want to make an offer on an NFT without that assets they are offering to leave their address until the sale is made atomically. + +#### Balance Snapshots + +An app that distributes token may want to reward token holders for holding any given token. Currently, this is impossible to do (without an off-chain system) due to the fact you cannot get historical account data (for assets or anything else). This could possibly be achieved if we had an on-chain light client that used state proofs as fraud proofs, but that has all the downsides of working with state proofs and optimistic systems (and not even possible right now). Snapshots can be done much more simply if tokens could have their own hook on every transfer that took balance snapshots to prove whether an account had a given balance in any period. + +### Removing Opt Ins + +ASA opt-ins add a lot of friction to the user experience. This is especially true for new-user onboarding. Having an asset that doesn't require an opt in would significantly improve the experience. That being said, we also want to maintain the ability to easily query all the assets a user holds. + +### On-Chain Metadata + +Having metadata on chain has two benefits: + +* This data can be set programmatically based on rules in a contract +* This data can be read in other on-chain applications + +## Architecture + +The interfaces for ARC-84 **MAY** be split across multiple apps. The singleton implementation proposed in this ARC uses two apps: The **Data App** and the **Transfer App**. A third optional app in this implementation called the **Transfer Hook App**. Transfers are initiated by calling a method on the **Transfer App**, with all data being stored on the **Data App**, which also does all the accounting. The **Transfer Hook App** **MAY** be used to attach additional logic to transfers and conditionally reject them. + +### The Apps + +```mermaid +classDiagram + +class TransferApp["Transfer App"] +class DataApp["Data App"] +class TransferHookApp["Transfer Hook App (Optional)"] + +TransferApp --> DataApp : Perform accounting for transfer +TransferApp --> TransferHookApp : Check for approval + +TransferApp : public arc84_transfer() + +DataApp : Token Metadata +DataApp : Token Params +DataApp : Collection Metadata +DataApp : Allowances +DataApp : Balances +DataApp : "protected" doTransfer() + +TransferHookApp : approved() +``` + +### Successful Transfer Sequence + +```mermaid +sequenceDiagram + actor User + User ->> Transfer App : call arc84_transfer() + Transfer App ->> Data App : call arc84_transferHookApp() + alt Has Transfer Hook App + Data App ->> Transfer App: Transfer Hook App ID + Transfer App ->> Transfer Hook App: call approved() + note over Transfer Hook App: MAY read data from Data App
MAY inspect ARC84 transfers + Transfer Hook App ->> Transfer App : true + else No Transfer Hook App + Data App ->> Transfer App: 0 + end + Transfer App ->> Data App : call doTransfer() + note over Data App: Asserts the caller is the Transfer App
Checks allowances
Performs accounting on balances + note over User: No error: transfer succesful! +``` + +## Specification + +### Transfer Interface + +#### ARC-56 Transfer Interface + +
+Click to reveal JSON + +```json +{ + "methods": [ + { + "name": "arc84_transfer", + "args": [ + { + "name": "dataApp", + "type": "uint64" + }, + { + "name": "transfers", + "type": "(uint64,address,address,uint64)[]" + } + ], + "returns": { + "type": "void" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + ] +} +``` + +
+ +#### TEALScript Transfer Interface Signatures + +```typescript +export type TokenId = uint64; + +export type Transfer = { + tokenId: TokenId; + from: Address; + to: Address; + amount: uint64; +}; + +arc84_transfer(dataApp: AppID, transfers: Transfer[]): void +``` + +### Data Interface + +#### ARC-56 Data Interface + +
+ Click to reveal JSON + +```json +{ + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "transferApp", + "type": "uint64" + } + ], + "returns": { + "type": "void" + }, + "actions": { + "create": [ + "NoOp" + ], + "call": [] + } + }, + { + "name": "arc84_newCollection", + "args": [ + { + "name": "manager", + "type": "address" + }, + { + "name": "mintCap", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_collection_minted", + "desc": "***************\nGetter Methods\n***************", + "args": [ + { + "name": "id", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_metadata", + "args": [ + { + "name": "key", + "type": "(uint64,byte[])", + "struct": "MetadataKey" + } + ], + "returns": { + "type": "(bool,byte[])", + "struct": "Metadata" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_balanceOf", + "args": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "account", + "type": "address" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_params", + "args": [ + { + "name": "id", + "type": "uint64" + } + ], + "returns": { + "type": "(byte[32],byte[8],uint64,uint64,address,uint64)", + "struct": "Params" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_transferApp", + "args": [], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_transferHookApp", + "args": [ + { + "name": "id", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_balancesOf", + "desc": "********************\nMulti Getter Methods\n********************", + "args": [ + { + "name": "idAndAddrs", + "type": "(uint64,address)[]" + } + ], + "returns": { + "type": "uint64[]" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_mulitpleParams", + "args": [ + { + "name": "ids", + "type": "uint64[]" + } + ], + "returns": { + "type": "(byte[32],byte[8],uint64,uint64,address,uint64)[]" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_setMetadata", + "desc": "***************\nSetter methods\n***************", + "args": [ + { + "name": "key", + "type": "(uint64,byte[])", + "struct": "MetadataKey" + }, + { + "name": "data", + "type": "byte[]" + } + ], + "returns": { + "type": "void" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_setAllowance", + "args": [ + { + "name": "allowanceKey", + "type": "(address,address,uint64)", + "struct": "AllowanceKey" + }, + { + "name": "allowance", + "type": "(uint64,uint64,uint64,uint64,uint64)", + "struct": "Allowance" + } + ], + "returns": { + "type": "void" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_setAllowances", + "desc": "********************\nMulti Setter Methods\n********************", + "args": [ + { + "name": "allowances", + "type": "((address,address,uint64),(uint64,uint64,uint64,uint64,uint64))[]" + } + ], + "returns": { + "type": "void" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "doTransfers", + "desc": "*********************\nTransfer/Mint Methods\n*********************", + "args": [ + { + "name": "sender", + "type": "address" + }, + { + "name": "transfers", + "type": "(uint64,address,address,uint64)[]" + } + ], + "returns": { + "type": "void" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "arc84_mint", + "args": [ + { + "name": "collectionId", + "type": "uint64" + }, + { + "name": "params", + "type": "(byte[32],byte[8],uint64,uint64,address,uint64)", + "struct": "Params" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + } + ] +} +``` + +
+ +#### TEALScript Data Interface Signatures + +```typescript + +export type Params = { + /** The descriptive name of the token */ + name: bytes<32>; + /** The short ticker symbol of the token */ + symbol: bytes<8>; + /** The total supply */ + total: uint64; + /** The number of digits to use after the decimal point when displaying the asset */ + decimals: uint64; + /** The address that can modify the token metadata */ + manager: Address; + /** The address of the app that implements the transfer hook. If this is not set, transfers are always approved */ + transferHookApp: AppID; +}; + +export type IdAndAddress = { + tokenId: TokenId; + address: Address; +}; + +export type MetadataKey = { + /** id for collection or token depending on context */ + id: uint64; + key: bytes; +}; + +export type Metadata = { + mutable: boolean; + data: bytes; +}; + +export type AllowanceKey = { + holder: Address; + sender: Address; + tokenId: TokenId; +}; + +export type Allowance = { + amount: uint64; + remainingAmount: uint64; + cooldown: uint64; + lastUsed: uint64; + expirationTimestamp: uint64; +}; + +export type Collection = { + /** The total number of tokens minted in this collection */ + minted: uint64; + + /** The cap to total tokens that can be minted */ + mintCap: uint64; + + /** The address that can modify collection metadata and mint new tokens */ + manager: Address; +}; + +arc84_newCollection(manager: Address, mintCap: uint64): CollectionId + +/** *************** +* Getter Methods +**************** */ + +arc84_collection_minted(id: CollectionId): uint64 + +arc84_metadata(key: MetadataKey): Metadata + +arc84_balanceOf(id: TokenId, account: Address): uint64 + +arc84_params(id: TokenId): Params + +arc84_transferApp(): AppID + +arc84_transferHookApp(id: TokenId): AppID + +/** ******************** +* Multi Getter Methods +********************* */ + +arc84_balancesOf(idAndAddrs: IdAndAddress[]): uint64[]): void + +arc84_mulitpleParams(ids: TokenId[]): Params[]): void + +// TODO: Multi-getter for metadata + +/** *************** +* Setter methods +**************** */ + +arc84_setMetadata(key: MetadataKey, data: bytes): void + +arc84_setAllowance(allowanceKey: AllowanceKey, allowance: Allowance): void + +/** ******************** +* Multi Setter Methods +********************* */ + +arc84_setAllowances(allowances: { key: AllowanceKey; allowance: Allowance }[]): void + +// TODO: Multi-setter for metadata + +/** ********************* +* Mint Methods +********************** */ + +arc84_mint(collectionId: CollectionId, params: Params): uint64 +``` + +## Rationale + +### Core Philosophy: Separate Representations of Same Asset + +A core philosophy of ARC-84 is that it is acceptable, if not preferable, to have different representations of the same asset for different contexts. In the many conversations regarding asset standards or ASA changes the developer ecosystem has had, we have tried to make a substantial change without breaking anything or having 100% transparent compatibility with ASAs. This goal has seemed to be impossible so far, so ARC-84 embraces the fact that there may be different representations of a given asset and attempts to have seamless conversions to ASAs, but not 100% compatibility. This is why ARC-84 uses `uint64` over `uint256` and enables compatibility with off-chain clients through parameters and metadata. The parameters of ARC-84 tokens also allow them to be easily bridged to ASAs. While ARC-84 tokens won't be directly compatible with existing smart contracts, we can provide the mechanisms for frontends to allow users to bridge between ARC-84 and ASAs seamlessly. + +For example, a user may want to have an ARC-84 representation of USDC that allows for useful features like automatic payments for a subscription service. This user may also want to use USDC in long-standing DeFi protocols and those protocols want to use ASAs due to their accounting guarantees. If they go to a DeFi frontend but only hold ARC-84 USDC, they should still be able to swap to the ASA within the same transaction group. Using approvals, this could even be done without any extra transactions for the user. This UX is possible with ARC-84, and as shown in the reference implementation, it is fairly low effort for dApp frontends to support this automatic bridging. + +### Singleton Data Contract With Transfer Hook: Trusted Accounting Logic + +One of the main goals of ARC-84 is to find a balance between trust and flexibility. With other smart contract tokens, you cannot have programmability and trust at the same time without building up a list of approved apps and/or programs (which then limits flexibility). ARC-84 allows singleton apps to implement transfer and data logic which only need to verified once by the community. Afterward, they can be trusted indefinitely due to the immutability of the contracts. To still allow programmability within this model, an additional app, the **Transfer Hook App**, can implement additional logic to approve or deny transactions, but it cannot break the accounting rules laid out in the singleton. By default the **Transfer Hook App**, cannot even perform transfers out-of-the-box, but automatic transfers from the transfer hook app are possible via the allowance system. + +### Separation of Transfer and Data Apps: Data Access In Transfer Hooks + +In order to accomplish the above point of trusted accounting logic and flexibility, we need to have an external app, the **Transfer Hook App**. This app can approve or deny transfers for a given token and app may also execute additional logic like snapshots or royalty enforcement. In order to do these functions effectively, it must have access to the token's data, which is held in the **Data App**. If the data app implement the transfer method, and thus the call to the transfer hook app directly, reading token data wouldn't be possible because re-entrancy is not allowed in the AVM. Having two apps lets us have one app, the transfer app, be responsible for transfers and calling the transfer hook app, while the data app is solely responsible for the accounting and storing data. This gives us full programmability without any re-entrancy. + +### Multiple Transfers Per Call: Atomicity & Readability + +Allowing multiple transfers in one method calls allows for more efficient transfers. A single method call can transfer any number of tokens between any number of accounts (within the resource limitations of the AVM). More importantly, having multiple transfers in a single calls allows for inspection of transfer groups by the **Transfer Hook App** that would otherwise be impossible due to the fact that inner transactions cannot access high-level transaction groups. This enables possibilities such as denying any transfer that doesn't include a royalty payment. + +### Allowances With Expiration & Cooldown: Safely Enable Delegation Features + +Approvals are a key feature of other smart contract tokens, such as ERC20 and ARC-200, but they have serious security implications. For example, a large amount of EVM exploits occur due to users giving protocols token approvals and that same protocol being exploited years later after they no longer us the protocol. This is the driving rationale for having an expiration time for allowances in ARC-84. By setting an expiration time, users can be sure a protocol will not have access to their tokens when they are done using the app without having to take any explicit action. Similarly, the cooldown mechanism enables a highly-requested feature, subscriptions, in a secure manner. By being supported directly in ARC-84, there is no implementation ambiguity and all apps in the ecosystem can clearly display allowance information to users. + +### App IDs to Identify Tokens: Ensures no ASA ID collision + +Each ARC-84 token is identified within its singleton data app via a `uint64` ID (and the combination of data app ID and token ID identify a token for the entire network). The implementation in this ARC uses application IDs to assign token IDs, rather than having a counter that increments each token mint. This is done to ensure that token IDs do not collide with ASA IDs, which enables backwards compatibility features further discussed in the next section + +### uint64 Accounting: Ensure Compatibility with ASAs + +Smart contract token standards on Algorand have to choose between `uint64` and `uint256` for supply and balance arithmetic. Past ARCs, such as ARC-200, have chosen `uint256` to align with EVM standards. This allows for a better bridging experience with non-AVM chains that use `uint256`, but hurts the compatibility with the current ASA-based ecosystem. This ARC prioritizes compatibility with the AVM ecosystem, thus uses `uint64` over `uint256`. Compatibility with non-AVM chains should be tackled as a separate problem. + +### Collections: On-Chain Guarantees for Valuable Collection Data + +The collection an NFT is in contributes to the value of the NFT, so it seems to make sense to include some guarantees about that collection on-chain. ARC-84 allows collections to have guaranteed immutability for metadata, a mint cap for tokens in a collection, and a manager address to control who can mint tokens in the collection and modify metadata. These primitive functionalities can be extended to offer as much if not more features than what is currently available through other ARCs such as ARC-53. + +## Backwards Compatibility + +### Contract Logic: Bridging ASAs + +ARC-84 tokens themselves are not intended to be compatible with existing ASA-based smart contract logic, but they are designed to be easily transferable to an ASA. This allows end users to use their assets with existing apps with minimal friction, regardless if they hold ASAs or ARC-84 tokens. To facilitate this user experience, there needs to be an on-chain bridge that can convert ASAs to ARC-84 tokens and vice-versa. The specifics of bridging is not part of this ARC, but a token that can easily be bridged is one of the main goals of this ARC. A non-normative reference implementation for a bridge, along with tests, can be found in the reference implementation section. + +#### Auto Bridging + +Bridging ARC-84 tokens to ASAs, should not only be possible, but it should be as seamless as possible for end users. They should not have to think how their assets are represented on-chain before using them. It should be easy for existing apps to integrate "auto bridge" functionality to their client-side code that automatically convers assets for users as needed. Much like bridging itself, this is a core design goal for this ARC. A non-normative reference implementation for auto-bridging can also be found in the reference implementation section. + +### ASA API Compatibility + +While ARC-84 tokens can't have direct compatibility with smart contract logic, it is possible to have direct compatibility with off-chain API endpoints for reading token data. The primary design feature that enables this is the fact that token IDs are unique uint64 IDs that cannot collide with ASA IDs (in the singleton implementation this ARC proposes). This means when one hits an ASA endpoint and the uint64 provided is not an asset, the API provided can fallback to checking the ARC-84 token without any additional input needed from the caller. + +#### Params & Metadata + +The parameters defined for ARC-84 align with ASA parameters: + +```typescript +export type Params = { + /** The descriptive name of the token */ + name: bytes<32>; + /** The short ticker symbol of the token */ + symbol: bytes<8>; + /** The total supply */ + total: uint64; + /** The number of digits to use after the decimal point when displaying the asset */ + decimals: uint64; + /** The address that can modify the token metadata */ + manager: Address; + /** The address of the app that implements the transfer hook. If this is not set, transfers are always approved */ + transferHookApp: AppID; +}; +``` + +It should be noted that the RBAC fields, such as `FreezeAddress` and `ClawbackAddress`, are NOT in ARC-84 as these features can be replicated by the transfer hook and allowance systems. + +#### Opt-In & Holding Discoverability + +A nice feature of ASAs for clients is that with a single API call you can get all the assets an address holds due to the opt-in mechanism. ARC-84 does not have a native opt-in mechanism, but an external singleton contract can be used as a registry for declaring holdings that wallets, explorers, and other apps can use. A non-normative reference implementation for this kind of app is in the reference implementation section. This pattern is not only useful for ARC-84, but any smart contract token where app IDs identity a single token. + +### ASA Transfer Compatibility + +Much like read-only ASA APIs, ARC-84 is designed to be compatible with ASA transfers. If a client, such as a wallet, attempts to send an `axfer` and the asset ID is an ARC-84 ID, the `axfer` can be translated to a `arc84_transfer` call. `sender`, `assetReceiver`, `assetSender` (with appropriate allowances), and `assetAmount` all translate directly to the `arc84_transfer` parameters. `closeAssetTo` is not a feature of ARC84, but can be replicated with a second atomic transfer in the same `arc84_transfer` call. + +Other ASA transactions, such as `acfg` or `afrz` don't have a direct translation, but this is deemed acceptable because these are actions that are often taken in the context of an application (and not from a general client like a wallet). + +## Test Cases +Test cases for an implementation are mandatory for ARCs that are affecting consensus changes. If the test suite is too large to reasonably be included inline, then consider adding it as one or more files in `../assets/arc-####/`. + +## Reference Implementation + +### ARC-84 Data App + +Data app with params, metadata, balances, and allowances stored in box storage. Implements all ARC-84 interfaces except `arc84_transfer`. + +[TEALScript Source Code](https://github.com/joe-p/arc84_poc/tree/main/projects/arc84_poc/contracts/ARC84Data.algo.ts) + +### ARC-84 Transfer App + +Transfer app that implements `arc84_transfer`. Assets the transfer hook app declared by the token in the data app returns true (if defined). + +[TEALScript Source Code](https://github.com/joe-p/arc84_poc/tree/main/projects/arc84_poc/contracts/ARC84Transfer.algo.ts) + +### ARC-84 Bridge + +Bridge between ARC-84 tokens and ASAs. + +TODO: Also bridge ASAs + +[TEALScript Source Code](https://github.com/joe-p/arc84_poc/tree/main/projects/arc84_poc/contracts/ARC84Bridge.algo.ts) + +### Auto Bridging: Tinyman Swap + +A demo showcasing how these few lines of code can add automatic ARC-84 to ASA bridging to perform a Tinyman swap + +```typescript +export async function monkeyPatchTinymanV2Swap(algod: algosdk.Algodv2, bridgeAppId: bigint) { + Swap.v2.generateTxns = async (params: GenerateSwapTxnsParams): Promise => { + const origGroup = await origSwapTxns(params) + + // autoArc84ToAsa is provided by a generic ARC84 library + const autoTxns = await autoArc84ToAsa( + origGroup.map((t) => t.txn), + algod, + bridgeAppId, + ) + + return autoTxns.map((t) => { + return { txn: t, signers: origGroup[0].signers } + }) + } +} +``` + +This reference implementation is done in TypeScript, which supports monkey-patching. The same concept, however, could be applied to any client written in any language. The core idea is that we take the transaction group before it is sent to users and check if they have enough ASA balance. If not, then check if they have ARC-84 tokens and do the swap if available. + +[TypeScript Source Code](https://github.com/joe-p/arc84_poc/tree/main/projects/demo/scripts/patched_swap.ts) + +### Declaration Registry + +Contract used to declare smart contract-based tokens, such as ARC-84, providing similar benefits to opt-in for clients reading chain data. + +[TEALScript Source Code](https://github.com/joe-p/arc84_poc/tree/main/projects/arc84_poc/contracts/DeclarationRegistry.algo.ts) + +## Security Considerations +All ARCs must contain a section that discusses the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surfaces risks and can be used throughout the life cycle of the proposal. E.g. include security-relevant design decisions, concerns, important discussions, implementation-specific guidance and pitfalls, an outline of threats and risks and how they are being addressed. ARC submissions missing the "Security Considerations" section will be rejected. An ARC cannot proceed to status "Final" without a Security Considerations discussion deemed sufficient by the reviewers. + +## Copyright +Copyright and related rights waived via CCO.