From b241dc9c39be62a43af477bd34c79abd6038cecf Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 7 Aug 2023 14:40:37 -0700 Subject: [PATCH] Granular Asset Minting (#491) ### Abstract This PR introduces granular asset minting which would enable sub identifiers to be included at asset creation. These sub identifiers can include important metadata and be used to enable native level NFTs. **This adds:** - A new asset ID construction (which incorporates the contract ID and the sub asset ID). - New receipt logs for minting and burning which are helpful for indexing. - Changes to the MINT and BURN opcodes. ### Cons - This removes the nice feature that asset IDs are the contract ID. ### Pros - Native level UTXO based NFTs. - Single contract multi-asset pools (useful for common AMM designs). Implementation tickets/PRs: - https://github.com/FuelLabs/fuel-vm/issues/496 - https://github.com/FuelLabs/fuels-ts/issues/1067 - https://github.com/FuelLabs/fuel-indexer/issues/1012 - https://github.com/FuelLabs/sway/pull/4651 --------- Co-authored-by: Brandon Kite Co-authored-by: Green Baneling --- src/abi/receipts.md | 42 ++++++++++++++++++++++ src/fuel-vm/instruction-set.md | 66 ++++++++++++++++++++++++---------- src/identifiers/asset.md | 8 +++++ src/identifiers/index.md | 3 +- src/tx-format/transaction.md | 2 ++ 5 files changed, 101 insertions(+), 20 deletions(-) create mode 100644 src/identifiers/asset.md diff --git a/src/abi/receipts.md b/src/abi/receipts.md index 32ff1bb2..1fbfdf7c 100644 --- a/src/abi/receipts.md +++ b/src/abi/receipts.md @@ -23,6 +23,8 @@ All receipts will have a `type` property: - [Panic](#panic-receipt) - [Revert](#revert-receipt) - [Log](#log-receipt) + - [Mint](#mint-receipt) + - [Burn](#burn-receipt) - [LogData](#logdata-receipt) - [Transfer](#transfer-receipt) - [TransferOut](#transferout-receipt) @@ -124,6 +126,46 @@ _Important note:_ For the JSON representation of receipts, we represent 64-bit u } ``` +## Mint Receipt + +- `type`: `Mint`. +- `sub_id`: Hexadecimal string representation of the 256-bit (32-byte) asset sub identifier ID; derived from register `$rB`. +- `contract_id`: Hexadecimal string representation of the 256-bit (32-byte) contract ID of the current context. +- `val`: Decimal string representation of a 64-bit unsigned integer; value of register `$rA`. +- `pc`: Hexadecimal string representation of a 64-bit unsigned integer; value of register `$pc`. +- `is`: Hexadecimal string representation of a 64-bit unsigned integer; value of register `$is`. + +```json +{ + "type": "Mint", + "sub_id": "0x39150017c9e38e5e280432d546fae345d6ce6d8fe4710162c2e3a95a6faff051", + "contract_id": "0x39150017c9e38e5e280432d546fae345d6ce6d8fe4710162c2e3a95a6faff051", + "val": "18446744073709551613", + "pc": "0xffffffffffffffff", + "is": "0xfffffffffffffffe" +} +``` + +## Burn Receipt + +- `type`: `Burn`. +- `sub_id`: Hexadecimal string representation of the 256-bit (32-byte) asset sub identifier ID; derived from register `$rB`. +- `contract_id`: Hexadecimal string representation of the 256-bit (32-byte) contract ID of the current context. +- `val`: Decimal string representation of a 64-bit unsigned integer; value of register `$rA`. +- `pc`: Hexadecimal string representation of a 64-bit unsigned integer; value of register `$pc`. +- `is`: Hexadecimal string representation of a 64-bit unsigned integer; value of register `$is`. + +```json +{ + "type": "Burn", + "sub_id": "0x39150017c9e38e5e280432d546fae345d6ce6d8fe4710162c2e3a95a6faff051", + "contract_id": "0x39150017c9e38e5e280432d546fae345d6ce6d8fe4710162c2e3a95a6faff051", + "val": "18446744073709551613", + "pc": "0xffffffffffffffff", + "is": "0xfffffffffffffffe" +} +``` + ## LogData Receipt - `type`: `LogData`. diff --git a/src/fuel-vm/instruction-set.md b/src/fuel-vm/instruction-set.md index 46204b2a..65c12b68 100644 --- a/src/fuel-vm/instruction-set.md +++ b/src/fuel-vm/instruction-set.md @@ -1626,23 +1626,37 @@ Block header hashes for blocks with height greater than or equal to current bloc ### BURN: Burn existing coins -| | | -|-------------|------------------------------------------------------| -| Description | Burn `$rA` coins of the current contract's asset ID. | -| Operation | ```burn($rA);``` | -| Syntax | `burn $rA` | -| Encoding | `0x00 rA - - -` | -| Notes | | +| | | +|-------------|-------------------------------------------------------------| +| Description | Burn `$rA` coins of the `$rB` ID from the current contract. | +| Operation | ```burn($rA, $rB);``` | +| Syntax | `burn $rA $rB` | +| Encoding | `0x00 rA rB - -` | +| Notes | `$rB` is a pointer to a 32 byte ID in memory. | + +The asset ID is constructed using the asset ID construction method. Panic if: -- Balance of asset ID `MEM[$fp, 32]` of output with contract ID `MEM[$fp, 32]` minus `$rA` underflows +- `$rB + 32 > VM_MAX_RAM` +- Balance of asset ID from `constructAssetID(MEM[$fp, 32], MEM[$rB, 32])` of output with contract ID `MEM[$fp, 32]` minus `$rA` underflows - `$fp == 0` (in the script context) -For output with contract ID `MEM[$fp, 32]`, decrease balance of asset ID `MEM[$fp, 32]` by `$rA`. +For output with contract ID `MEM[$fp, 32]`, decrease balance of asset ID `constructAssetID(MEM[$fp, 32], MEM[$rB, 32])` by `$rA`. This modifies the `balanceRoot` field of the appropriate output. +Append a receipt to the list of receipts, modifying tx.receiptsRoot: + +| name | type | description | +|----------|---------------|---------------------------------------------------------------------------| +| `type` | `ReceiptType` | `ReceiptType.Burn` | +| `sub_id` | `byte[32]` | Asset sub identifier `MEM[$rB, $rB + 32]`. | +| `contract_id` | `byte[32]` | Contract ID of the current context. | +| `val` | `uint64` | Value of register `$rA`. | +| `pc` | `uint64` | Value of register `$pc`. | +| `is` | `uint64` | Value of register `$is`. | + ### CALL: Call contract | | | @@ -1854,27 +1868,41 @@ Logs the memory range `MEM[$rC, $rD]`. Panics if: - `$rC + $rD` overflows -- `$rA + $rD > VM_MAX_RAN` +- `$rA + $rD > VM_MAX_RAM` ### MINT: Mint new coins -| | | -|-------------|------------------------------------------------------| -| Description | Mint `$rA` coins of the current contract's asset ID. | -| Operation | ```mint($rA);``` | -| Syntax | `mint $rA` | -| Encoding | `0x00 rA - - -` | -| Notes | | +| | | +|-------------|-------------------------------------------------------------| +| Description | Mint `$rA` coins of the `$rB` ID from the current contract. | +| Operation | ```mint($rA, $rB);``` | +| Syntax | `mint $rA $rB` | +| Encoding | `0x00 rA rB - -` | +| Notes | `$rB` is a pointer to a 32 byte ID in memory | + +The asset ID will be constructed using the asset ID construction method. Panic if: -- Balance of asset ID `MEM[$fp, 32]` of output with contract ID `MEM[$fp, 32]` plus `$rA` overflows +- `$rB + 32 > VM_MAX_RAM` +- Balance of asset ID `constructAssetID(MEM[$fp, 32], MEM[$rB])` of output with contract ID `MEM[$fp, 32]` plus `$rA` overflows - `$fp == 0` (in the script context) -For output with contract ID `MEM[$fp, 32]`, increase balance of asset ID `MEM[$fp, 32]` by `$rA`. +For output with contract ID `MEM[$fp, 32]`, increase balance of asset ID `constructAssetID(MEM[$fp, 32], MEM[$rB])` by `$rA`. This modifies the `balanceRoot` field of the appropriate output. +Append a receipt to the list of receipts, modifying tx.receiptsRoot: + +| name | type | description | +|----------|---------------|---------------------------------------------------------------------------| +| `type` | `ReceiptType` | `ReceiptType.Mint` | +| `sub_id` | `byte[32]` | Asset sub identifier `MEM[$rB, $rB + 32]`. | +| `contract_id` | `byte[32]` | Contract ID of the current context. | +| `val` | `uint64` | Value of register `$rA`. | +| `pc` | `uint64` | Value of register `$pc`. | +| `is` | `uint64` | Value of register `$is`. | + ### RETD: Return from context with data | | | diff --git a/src/identifiers/asset.md b/src/identifiers/asset.md new file mode 100644 index 00000000..7f51fb51 --- /dev/null +++ b/src/identifiers/asset.md @@ -0,0 +1,8 @@ +# Asset ID + +The _asset ID_ (also called _asset hash_) of a asset is computed as +the [hash](../protocol/cryptographic-primitives.md#hashing) of the `CONTRACT_ID` and a 256-bit `SUB_IDENTIFIER`. + +```python +sha256(CONTRACT_ID ++ SUB_IDENTIFIER) +``` diff --git a/src/identifiers/index.md b/src/identifiers/index.md index 4cd66523..0cff02bb 100644 --- a/src/identifiers/index.md +++ b/src/identifiers/index.md @@ -2,9 +2,10 @@ This chapter defines how to compute unique identifiers. -- [Transaction ID](./transaction-id.md) +- [Asset ID](./asset.md) - [Contract ID](./contract-id.md) - [Predicate ID](./predicate-id.md) +- [Transaction ID](./transaction-id.md) - [UTXO ID](./utxo-id.md) - [Coin ID](./utxo-id.md#coin-id) - [Message ID](./utxo-id.md#message-id) diff --git a/src/tx-format/transaction.md b/src/tx-format/transaction.md index c9c9278c..3ece7d46 100644 --- a/src/tx-format/transaction.md +++ b/src/tx-format/transaction.md @@ -51,6 +51,8 @@ enum ReceiptType : uint8 { TransferOut = 8, ScriptResult = 9, MessageOut = 10, + Mint = 11 + Burn = 12 } ```