From 5a45c8d6496dd92927b4288ad42129cfec700b9d Mon Sep 17 00:00:00 2001 From: Rob Konsdorf Date: Tue, 18 Aug 2026 17:06:33 -0400 Subject: [PATCH] docs: move both contract baselines to the GA v2.0.0 tags The release candidates the corpus pinned are superseded: both contracts tagged v2.0.0 and the GA AtomicAssets build is what the testnets execute, byte-verified against the Release checksum. atomicmarket v2.0.0 is the same commit as rc2. The atomicassets GA diff moves every citation past the acceptauswap hunk by three lines and accepts the acceptance-date boundary second the candidates rejected, so the affected sections state the GA behavior and every shifted citation was re-verified against the tag. --- AGENTS.md | 2 +- CHANGELOG.md | 16 ++++ README.md | 4 +- guides/asset-lifecycle.md | 20 ++--- guides/auctions.md | 4 +- guides/buyoffers.md | 4 +- guides/deposits.md | 2 +- guides/notification-integration.md | 18 ++--- guides/offers.md | 16 ++-- guides/querying-the-api.md | 2 +- guides/sales.md | 4 +- reference/atomicassets/actions.md | 78 ++++++++++---------- reference/atomicassets/backing-tokens.md | 12 +-- reference/atomicassets/custom-types.md | 8 +- reference/atomicassets/data-precedence.md | 8 +- reference/atomicassets/notifications.md | 12 +-- reference/atomicassets/serialization.md | 8 +- reference/atomicassets/structure.md | 12 +-- reference/atomicassets/tables.md | 24 +++--- reference/atomicassets/v2-upgrade.md | 6 +- reference/atomicmarket/actions.md | 2 +- reference/atomicmarket/fees-and-royalties.md | 2 +- reference/atomicmarket/marketplaces.md | 2 +- reference/atomicmarket/ram.md | 2 +- reference/atomicmarket/tables.md | 2 +- reference/atomicmarket/v2-changes.md | 2 +- reference/media.md | 2 +- reference/validation.md | 50 ++++++------- tutorials/first-collection.md | 2 +- 29 files changed, 173 insertions(+), 153 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 67d8845..3527955 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,6 +64,6 @@ Read the routed file in full rather than searching it. The facts there encode be Take each section at face value and do not extrapolate past what it states. A page says what was checked, and what it does not say was not checked. `reference/validation.md` records how every page was validated and against what. It grades `reference/` and `guides/` only: a tutorial's claim is that its steps run, and a concepts page restates facts the pages it links already carry, so neither takes a row there. -Re-check any fact that names a version when that dependency moves. The two SDK pages are pinned to `@atomichub/atomicassets` 2.1.1, read at tag `v2.1.1`, and `@atomichub/atomicmarket` 2.4.1, read at tag `v2.4.1`; the client-library page is pinned to `@wharfkit/antelope` 1.1.1, and the AtomicAssets and AtomicMarket contract pages to `v2.0.0-rc4` and `v2.0.0-rc2`. A fact read at one of those pins is a fact about that release, not about the package name. +Re-check any fact that names a version when that dependency moves. The two SDK pages are pinned to `@atomichub/atomicassets` 2.1.1, read at tag `v2.1.1`, and `@atomichub/atomicmarket` 2.4.1, read at tag `v2.4.1`; the client-library page is pinned to `@wharfkit/antelope` 1.1.1, and the AtomicAssets and AtomicMarket contract pages to `v2.0.0` and `v2.0.0`. A fact read at one of those pins is a fact about that release, not about the package name. Two skills sit beside these pages. `skills/atomic-integration/SKILL.md` carries the procedures a routing table cannot: the mint flow, the market composers, and the network choice. `skills/report/SKILL.md` writes a difficulty report when a page here turned out wrong, missing, or misleading, in the field shape this repository's issue forms accept. diff --git a/CHANGELOG.md b/CHANGELOG.md index 169ef1a..fe1f6e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ What each release of this corpus changed, one release per tag. `Corrected` comes first in every release, because a fact that was wrong is what a returning reader has to see before anything else. The other sections are `Added`, `Revalidated`, and `Removed`, in that order, and a section with nothing in it is left out. +## 2026.08.1 + +### Corrected + +- `reference/atomicassets/actions.md` states the GA acceptance boundary for `acceptauswap`: the boundary second is accepted, and the note about a source comment the GA release fixed is gone. +- `reference/atomicassets/tables.md` marks `acceptance_date` as the second at or after which `acceptauswap` is callable. +- `reference/atomicassets/actions.md` and `reference/atomicassets/tables.md` cite `internal_create_template` at its real bounds, which the previous citation missed on both ends. + +### Added + +- `reference/atomicassets/v2-upgrade.md` records that both testnets run the GA build byte for byte: the live `get_code_hash` equals the `v2.0.0` Release checksum. + +### Revalidated + +- Every page pinned to a contract release candidate now reads at the GA `v2.0.0` tags: `atomicmarket-contract` `v2.0.0` is the same commit as `v2.0.0-rc2`, and every `atomicassets-contract` citation was re-anchored and re-verified across the GA diff. + ## 2026.08.0 ### Corrected diff --git a/README.md b/README.md index b44390d..53dac84 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ Agents read `AGENTS.md`, whose routing table maps a task to the file that answer The pages are read against these baselines: -- `atomicassets-contract` at `v2.0.0-rc4` -- `atomicmarket-contract` at `v2.0.0-rc2` +- `atomicassets-contract` at `v2.0.0` +- `atomicmarket-contract` at `v2.0.0` - `atomicassets-api` at its `main` branch state, which carries no release tag; the streaming and rate-limit pages pin commit `f6419858` - `atomictools-contract` at commit `d89ce79e4`, which the deployed `atomictoolsx` ABI on WAX matches exactly - `atomicassets-sdk` at main `80580c5` and `atomicmarket-sdk` at main `278bdfa`, both version 2.0.0 diff --git a/guides/asset-lifecycle.md b/guides/asset-lifecycle.md index ec0fbdf..b1fb068 100644 --- a/guides/asset-lifecycle.md +++ b/guides/asset-lifecycle.md @@ -2,14 +2,14 @@ scope: Creator flow on the `atomicassets` contract - create a collection, define a schema, optionally a template, mint assets, edit mutable data, transfer, and burn depends-on: [reference/atomicassets/structure.md, reference/atomicassets/actions.md, reference/wharfkit.md] key-modules: - - "atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp" - - "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp" + - "atomicmarket-contract (v2.0.0): src/atomicmarket.cpp" + - "atomicassets-contract (v2.0.0): src/atomicassets.cpp" - "@atomichub/atomicassets 2.1.1 (atomicassets-sdk v2.1.1, 5c70c62): src/Actions/Generator.ts" --- # Create a collection and mint assets -The full creator flow on the `atomicassets` contract: create a collection, define a schema, optionally create a template, mint assets, edit mutable data, transfer, and burn. Baseline is AtomicAssets V2; notes call out where V1 differed. Every data shape, required authorization, RAM payer, and failure mode below was checked against tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets), `src/atomicassets.cpp`. +The full creator flow on the `atomicassets` contract: create a collection, define a schema, optionally create a template, mint assets, edit mutable data, transfer, and burn. Baseline is AtomicAssets V2; notes call out where V1 differed. Every data shape, required authorization, RAM payer, and failure mode below was checked against tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets), `src/atomicassets.cpp`. Each step shows the action's data as plain JSON first, then the same call through `@wharfkit/session`'s `session.transact()`. See [Build a session and sign](signing.md) for how that `session` is constructed and which chain it points at. `ATTRIBUTE_MAP` fields (`data`, `immutable_data`, `mutable_data`) serialize as an array of `{key, value}` pairs, where `value` is a two-element `[type, value]` variant. The `key`/`value` naming is only present in the patched release ABI; the raw CDT build names the same fields `first`/`second`. See [Contract releases and deployment](../reference/contract-releases.md#raw-vs-patched-abi) ("Raw vs patched ABI"). @@ -65,7 +65,7 @@ await session.transact({ - RAM payer: `author`. - Fails when: a collection with this name already exists (`"A collection with this name already exists"`); `notify_accounts` is non-empty while `allow_notify` is false (`"Can't add notify_accounts if allow_notify is false"`); `authorized_accounts` or `notify_accounts` contains a nonexistent account or a duplicate; `market_fee` is outside `0` to `0.15` (the message is built with `std::to_string` of the `double` bound, so at runtime it reads `"The market_fee must be between 0 and 0.150000"`); or a `data` attribute named `name` exceeds 64 characters (`"Names (attribute with name: \"name\") can only be 64 characters max"`). -Source: `atomicassets-contract src/atomicassets.cpp:91-158` (`createcol`), `atomicassets-contract src/atomicassets.cpp:141-142` (market_fee bound), `atomicassets-contract include/atomicassets.hpp:13` (`MAX_MARKET_FEE`), `atomicassets-contract src/atomicassets.cpp:1895-1905` (`check_name_length`) +Source: `atomicassets-contract src/atomicassets.cpp:91-158` (`createcol`), `atomicassets-contract src/atomicassets.cpp:141-142` (market_fee bound), `atomicassets-contract include/atomicassets.hpp:13` (`MAX_MARKET_FEE`), `atomicassets-contract src/atomicassets.cpp:1898-1908` (`check_name_length`) ## Create a schema: createschema @@ -108,7 +108,7 @@ await session.transact({ - RAM payer: `authorized_creator`. - Fails when: the caller isn't an authorized account for the collection (`"Missing authorization for this collection"`); `schema_name` isn't 1 to 12 characters; a schema with this name already exists for the collection; any line's `type` isn't a recognized scalar or vector type, or a name is empty, over 64 characters, or duplicated; or the format omits a line with `name: "name"` and `type: "string"` (`"A format line with {\"name\": \"name\" and \"type\": \"string\"} needs to be defined for every schema"`). -Source: `atomicassets-contract src/atomicassets.cpp:450-475` (`createschema`), `atomicassets-contract src/atomicassets.cpp:1861-1875` (`check_has_collection_auth`, collection authorization), `atomicassets-contract include/checkformat.hpp:32-97` (format validation) +Source: `atomicassets-contract src/atomicassets.cpp:453-478` (`createschema`), `atomicassets-contract src/atomicassets.cpp:1864-1878` (`check_has_collection_auth`, collection authorization), `atomicassets-contract include/checkformat.hpp:32-97` (format validation) ## Create a template: createtempl @@ -157,7 +157,7 @@ await session.transact({ - RAM payer: `authorized_creator`. - Fails when: no schema with `schema_name` exists for the collection; both `transferable` and `burnable` are false (`"A template cannot be both non-transferable and non-burnable"`); or an `immutable_data`/`mutable_data` attribute named `name` exceeds 64 characters. `max_supply: 0` is valid and means unlimited. -Source: `atomicassets-contract src/atomicassets.cpp:566-576` (`createtempl`), `atomicassets-contract src/atomicassets.cpp:1579-1655` (`internal_create_template`, shared by `createtempl`/`createtempl2`) +Source: `atomicassets-contract src/atomicassets.cpp:569-579` (`createtempl`), `atomicassets-contract src/atomicassets.cpp:1582-1658` (`internal_create_template`, shared by `createtempl`/`createtempl2`) ## Mint an asset: mintasset @@ -202,7 +202,7 @@ Pass `template_id: -1` to mint a templateless asset carrying its own `immutable_ **Changed in V2:** native token backing (the `tokens_to_back` parameter and the `backasset` action) is deprecated: any non-empty `tokens_to_back` aborts the mint, and `backasset` unconditionally fails. Under V1 both were functional and moved real token balances onto the asset. -Source: `atomicassets-contract src/atomicassets.cpp:697-788` (`mintasset`, backing guard at `:786-787`), V1 backing behavior in this repo's V1 tree (`contracts/atomicassets-contract/src/atomicassets.cpp`) +Source: `atomicassets-contract src/atomicassets.cpp:700-791` (`mintasset`, backing guard at `:789-790`), V1 backing behavior in this repo's V1 tree (`contracts/atomicassets-contract/src/atomicassets.cpp`) ### Building the same mint through the SDK @@ -267,7 +267,7 @@ Pass `asset_id` as a string in the action data. See [AtomicMarket V2 changes](.. - RAM payer: reassigned to `authorized_editor` on every call (`_asset.ram_payer = authorized_editor`), replacing whoever paid before, including the original minter. - Fails when: no asset with `asset_id` exists for `asset_owner`; the caller isn't authorized for the asset's collection; or a `new_mutable_data` attribute named `name` exceeds 64 characters. -Source: `atomicassets-contract src/atomicassets.cpp:796-836` +Source: `atomicassets-contract src/atomicassets.cpp:799-839` ## Transfer an asset: transfer @@ -300,7 +300,7 @@ await session.transact({ - RAM payer: unchanged for an existing scope; the row keeps whoever originally paid for it. If `to` has never held any AtomicAssets asset before, a new scope must be created, and `from` implicitly pays for it (the transfer aborts if `from` hasn't authorized the action, which it always has, since `from` is the one calling `transfer`). - Fails when: `to` isn't a registered account; `from` equals `to`; `asset_ids` is empty or contains a repeated id; the memo exceeds 256 characters; `from` doesn't own one of the listed assets (`"Sender doesn't own at least one of the provided assets"`); or at least one asset's template has `transferable: false` (`"At least one asset isn't transferable"`). The contract appends the offending id to both of these messages as a ` (ID: )` suffix, so a match on either string should allow for the trailing id. -Source: `atomicassets-contract src/atomicassets.cpp:76-86` (`transfer` action), `atomicassets-contract src/atomicassets.cpp:1665-1761` (`internal_transfer`, shared with `acceptoffer`) +Source: `atomicassets-contract src/atomicassets.cpp:76-86` (`transfer` action), `atomicassets-contract src/atomicassets.cpp:1668-1764` (`internal_transfer`, shared with `acceptoffer`) ## Burn an asset: burnasset @@ -329,7 +329,7 @@ await session.transact({ - RAM payer: none afterward; the row and its RAM are released back to whoever paid for it. If the asset carries any `backed_tokens`, `burnasset` credits them to the owner's `balances` row before erasing the asset. That crediting code is retained in V2, so a legacy V1-backed asset still pays out its backing on burn; V2 only makes new backing impossible (`backasset` aborts and `mintasset` rejects a non-empty `tokens_to_back`), so no freshly-minted asset can accumulate a balance to release. - Fails when: no asset with `asset_id` exists for `asset_owner`, or the asset's template has `burnable: false` (`"The asset is not burnable"`). Templateless assets (`template_id: -1`) are always burnable. -Source: `atomicassets-contract src/atomicassets.cpp:1096-1177` (`burnasset`, backed-token crediting at `:1112-1145`) +Source: `atomicassets-contract src/atomicassets.cpp:1099-1180` (`burnasset`, backed-token crediting at `:1115-1148`) ## See also diff --git a/guides/auctions.md b/guides/auctions.md index eab8d2b..8d2fa1e 100644 --- a/guides/auctions.md +++ b/guides/auctions.md @@ -2,8 +2,8 @@ scope: AtomicMarket auction lifecycle on the V2 baseline - announce, transfer the asset into escrow, place deposit-backed bids, claim after the end, and cancel depends-on: [reference/atomicmarket/actions.md, guides/deposits.md] key-modules: - - "atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp" - - "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp" + - "atomicmarket-contract (v2.0.0): src/atomicmarket.cpp" + - "atomicassets-contract (v2.0.0): src/atomicassets.cpp" - "@atomichub/atomicmarket 2.4.1 (atomicmarket-sdk v2.4.1, 437300b): src/Actions/Generator.ts" --- diff --git a/guides/buyoffers.md b/guides/buyoffers.md index 232fa08..67f91df 100644 --- a/guides/buyoffers.md +++ b/guides/buyoffers.md @@ -2,8 +2,8 @@ scope: How to create, accept, decline, and cancel AtomicMarket asset and template buyoffers, whose price leaves the buyer's deposited balance at creation depends-on: [reference/atomicmarket/actions.md, guides/deposits.md, reference/api.md] key-modules: - - "atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp" - - "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp" + - "atomicmarket-contract (v2.0.0): src/atomicmarket.cpp" + - "atomicassets-contract (v2.0.0): src/atomicassets.cpp" - "@atomichub/atomicmarket 2.4.1 (atomicmarket-sdk v2.4.1, 437300b): src/Actions/Generator.ts" --- diff --git a/guides/deposits.md b/guides/deposits.md index 3da153d..2e47a10 100644 --- a/guides/deposits.md +++ b/guides/deposits.md @@ -1,7 +1,7 @@ --- scope: AtomicMarket's internal balances ledger - depositing with the transfer memo, what consumes a balance, withdrawing, who pays RAM, and supported tokens depends-on: [reference/atomicmarket/actions.md, reference/atomicmarket/ram.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp", "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp", "atomicassets-contract (v2.0.0): src/atomicassets.cpp"] --- # Balances and deposits diff --git a/guides/notification-integration.md b/guides/notification-integration.md index c771c02..a747c4d 100644 --- a/guides/notification-integration.md +++ b/guides/notification-integration.md @@ -1,12 +1,12 @@ --- scope: Building a third-party contract that reacts to AtomicAssets notifications - which ones reach a listener, how to wire on_notify, and the safety rules depends-on: [reference/atomicassets/notifications.md, reference/atomicassets/actions.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # React to contract notifications -A smart contract can react to AtomicAssets activity by receiving the `require_recipient` notifications the contract emits: a listener contract watches transfers, mints, or burns and runs its own logic the moment they happen, without polling the chain. This guide covers which notifications a third-party contract can receive, how to wire the C++ `on_notify` handlers so they actually fire, and the same-transaction safety rules that govern what a handler may safely do. It builds on [AtomicAssets notifications](../reference/atomicassets/notifications.md), which is the reference for the collection-config side (`notify_accounts`, `allow_notify`) and the full per-action notification map; read that first, then this for the integration mechanics. Baseline is the V2 contract, tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets). +A smart contract can react to AtomicAssets activity by receiving the `require_recipient` notifications the contract emits: a listener contract watches transfers, mints, or burns and runs its own logic the moment they happen, without polling the chain. This guide covers which notifications a third-party contract can receive, how to wire the C++ `on_notify` handlers so they actually fire, and the same-transaction safety rules that govern what a handler may safely do. It builds on [AtomicAssets notifications](../reference/atomicassets/notifications.md), which is the reference for the collection-config side (`notify_accounts`, `allow_notify`) and the full per-action notification map; read that first, then this for the integration mechanics. Baseline is the V2 contract, tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets). ## Which notifications a listener can receive @@ -16,13 +16,13 @@ There are two independent ways a third-party contract gets notified, and they ca Some actions call `require_recipient` on the specific accounts involved, so a listener that is one of those accounts is notified even without any collection opt-in. `transfer` notifies both `from` and `to`: a contract set as the recipient of a transfer receives the `atomicassets::transfer` notification with the transfer's own parameters. `mintasset` notifies the `new_asset_owner` through its inline `logmint` action, so a contract that assets are minted directly to is notified as the owner. Offer creation notifies the offer's `sender` and `recipient` through `lognewoffer`. None of these require the listener to be on any collection list; being the party named in the action is enough. -Source: `atomicassets-contract src/atomicassets.cpp:76-86` (`transfer`, `require_recipient(from)` and `require_recipient(to)` at `:83-84`), `atomicassets-contract src/atomicassets.cpp:1488-1505` (`logmint`, `require_recipient(new_asset_owner)` at `:1502`), `atomicassets-contract src/atomicassets.cpp:1457-1469` (`lognewoffer`) +Source: `atomicassets-contract src/atomicassets.cpp:76-86` (`transfer`, `require_recipient(from)` and `require_recipient(to)` at `:83-84`), `atomicassets-contract src/atomicassets.cpp:1491-1508` (`logmint`, `require_recipient(new_asset_owner)` at `:1505`), `atomicassets-contract src/atomicassets.cpp:1460-1472` (`lognewoffer`) ### Indirectly, as a collection notify account A collection author can add a contract to that collection's `notify_accounts` list (gated by `allow_notify`), and the contract is then notified on every collection-touching action through the inline `log*` action that fans out to `notify_collection_accounts`. This is how a listener observes activity for assets it does not own: mints, burns, transfers, data edits, and RAM-payer reassignments across the whole collection. The listener does not choose to subscribe; the collection author adds it, which is a deliberate trust grant, because a notify account's handler runs inside the triggering transaction and can make that action fail. The config side (adding and removing accounts, the one-way `forbidnotify` gate, the 24-account cap) is documented in [AtomicAssets notifications](../reference/atomicassets/notifications.md); this guide assumes the account is already on the list and focuses on the receiving contract. -Source: `atomicassets-contract src/atomicassets.cpp:1880-1888` (`notify_collection_accounts`), `atomicassets-contract src/atomicassets.cpp:246-279` (`addnotifyacc`, and its comment: "NOTE: It will consequently allow the account to make any of these actions throw (fail). Only add trusted accounts to this list") +Source: `atomicassets-contract src/atomicassets.cpp:1883-1891` (`notify_collection_accounts`), `atomicassets-contract src/atomicassets.cpp:246-279` (`addnotifyacc`, and its comment: "NOTE: It will consequently allow the account to make any of these actions throw (fail). Only add trusted accounts to this list") The full table of which action notifies whom, and by which mechanism, is in [AtomicAssets notifications](../reference/atomicassets/notifications.md#which-actions-notify-whom) ("Which actions notify whom"). The listener sees no difference in wiring between the two paths: both arrive as an `on_notify` dispatch on some action name. What differs is the action name to bind and the data delivered. @@ -52,7 +52,7 @@ The trap: the handler's parameter list must match the notifying action's ABI par The data a handler receives is exactly the notifying action's parameters, nothing more. `logtransfer` carries the moved `asset_ids` but not their templates or backed tokens; `logburnasset` is the richest, carrying the burned asset's full deserialized immutable and mutable data plus its backed tokens, because after the burn the row is gone and this is the only place that data survives. A handler that needs anything beyond what its signature delivers must read the AtomicAssets tables itself within the same transaction. -Source: `atomicassets-contract include/atomicassets.hpp:30-35` (`transfer`), `atomicassets-contract include/atomicassets.hpp:247-253` (`logtransfer`), `atomicassets-contract include/atomicassets.hpp:275-286` (`logmint`), `atomicassets-contract include/atomicassets.hpp:316-326` (`logburnasset`), `atomicassets-contract include/atomicassets.hpp:288-293` (`logsetdata`), `atomicassets-contract include/atomicassets.hpp:303-308` (`logrampayer`), `atomicassets-contract src/atomicassets.cpp:1752-1760` (per-collection `logtransfer` fan-out) +Source: `atomicassets-contract include/atomicassets.hpp:30-35` (`transfer`), `atomicassets-contract include/atomicassets.hpp:247-253` (`logtransfer`), `atomicassets-contract include/atomicassets.hpp:275-286` (`logmint`), `atomicassets-contract include/atomicassets.hpp:316-326` (`logburnasset`), `atomicassets-contract include/atomicassets.hpp:288-293` (`logsetdata`), `atomicassets-contract include/atomicassets.hpp:303-308` (`logrampayer`), `atomicassets-contract src/atomicassets.cpp:1755-1763` (per-collection `logtransfer` fan-out) ## Semantics and safety @@ -66,25 +66,25 @@ Source: `atomicassets-contract src/atomicassets.cpp:246-250` (`addnotifyacc` war The robust way to know a notification is genuine is that the dispatch itself binds it: an `on_notify("atomicassets::transfer")` handler only runs because the AtomicAssets contract sent the notification, so the notifier's identity is established by the binding, not by anything in the parameters. AtomicAssets models this in its own token-deposit handler: when it receives a `*::transfer` notification it authenticates the sending token contract with `get_first_receiver()` rather than trusting the transfer's fields, and it guards `if (to != get_self()) return;` so it only acts when it is the actual recipient. A listener bound to a single `contract::action` already knows the notifier, but the role guard matters: `transfer` notifies both `from` and `to`, so a handler is invoked in both roles and must check which one it is (`to == get_self()` for incoming) before acting. Do not treat the account names in the payload as authenticated identities to make trust decisions about; they are data describing the action, not proof that any of those accounts authorized your handler. -Source: `atomicassets-contract src/atomicassets.cpp:1402-1416` (`receive_token_transfer`: `to != get_self()` guard at `:1403`, `get_first_receiver()` authentication at `:1412`) +Source: `atomicassets-contract src/atomicassets.cpp:1405-1419` (`receive_token_transfer`: `to != get_self()` guard at `:1406`, `get_first_receiver()` authentication at `:1415`) ### Authorization context Assume none of the notified parties authorized your handler. The precise authorizations visible inside an Antelope notification handler are a property of the chain runtime (nodeos), not of the pinned AtomicAssets source, so this guide does not assert a line-cited rule about what `require_auth` returns in that context. The safe practice, and the one AtomicAssets follows in its own code, is to not attempt to authenticate a notified party by calling `require_auth` on a name from the payload: a handler establishes trust from the notifier binding (above), not by re-checking the user's authority. Where the contract needs its own authority, it uses `get_self()` (as every `log*` action does with `require_auth(get_self())`), never the notified user's. Design the handler to need only its own authorization plus the delivered data. -Source: `atomicassets-contract src/atomicassets.cpp:1452` (`logtransfer` uses `require_auth(get_self())`), `atomicassets-contract src/atomicassets.cpp:1500` (`logmint` likewise); Antelope runtime authorization semantics are not covered by the pinned contract source and are stated here as safe practice, not a source-cited fact. +Source: `atomicassets-contract src/atomicassets.cpp:1455` (`logtransfer` uses `require_auth(get_self())`), `atomicassets-contract src/atomicassets.cpp:1503` (`logmint` likewise); Antelope runtime authorization semantics are not covered by the pinned contract source and are stated here as safe practice, not a source-cited fact. ### RAM Your handler bills its own account for the rows it stores. A row a handler emplaces into its own tables is paid for by whoever the handler names as payer. The general Antelope rule about which payer a notification context may bill is a runtime property, not something the pinned source states, so treat it conservatively: pay RAM from `get_self()` for anything the listener stores, rather than trying to bill a user who merely appears in the notification. AtomicAssets' own deposit handler never opens a new user-billed row from the notification path; it modifies an already-existing balance row with `same_payer` and requires the row to have been created earlier by a separate user-authorized `announcedepo`. A listener that accumulates state should budget for that RAM on its own account, the same way the worked example below emplaces under `get_self()`. -Source: `atomicassets-contract src/atomicassets.cpp:1435-1437` (`receive_token_transfer` modifies with `same_payer`), `atomicassets-contract src/atomicassets.cpp:1418-1421` (deposit requires the pre-existing row); the general RAM-payer rule for notification contexts is Antelope runtime behavior, stated here as safe practice. +Source: `atomicassets-contract src/atomicassets.cpp:1438-1440` (`receive_token_transfer` modifies with `same_payer`), `atomicassets-contract src/atomicassets.cpp:1421-1424` (deposit requires the pre-existing row); the general RAM-payer rule for notification contexts is Antelope runtime behavior, stated here as safe practice. ### Inline follow-up actions stay in the transaction Deferring work to a self-inline action does not decouple it from the transaction. A handler can organize its follow-up work by sending an inline action to itself (`action(permission_level{get_self(), "active"}, ...).send()`), which is exactly how AtomicAssets dispatches its own `log*` actions. This gives the follow-up a clean authorization context (it runs as `get_self()`) and keeps the handler body small, but it does not make the work asynchronous: an inline action executes in the same transaction and still aborts the user's action if it throws. There is no built-in escape from the same-transaction rule in the notification path. Use a self-inline action for code structure and authorization clarity, not as a way to make a risky handler safe to fail. -Source: `atomicassets-contract src/atomicassets.cpp:1752-1760` (AtomicAssets sends its own `logtransfer` as an inline action under `get_self()`), `atomicassets-contract src/atomicassets.cpp:1655-1663` (`RAM_RESTRICTIONS` note on same-transaction inline behavior) +Source: `atomicassets-contract src/atomicassets.cpp:1755-1763` (AtomicAssets sends its own `logtransfer` as an inline action under `get_self()`), `atomicassets-contract src/atomicassets.cpp:1658-1666` (`RAM_RESTRICTIONS` note on same-transaction inline behavior) ## A minimal listener: counting incoming transfers diff --git a/guides/offers.md b/guides/offers.md index a465caf..8f39419 100644 --- a/guides/offers.md +++ b/guides/offers.md @@ -1,12 +1,12 @@ --- scope: The `atomicassets` createoffer, acceptoffer, declineoffer, and canceloffer trade primitive, what invalidates an offer, and how AtomicMarket sales use it depends-on: [reference/atomicassets/actions.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp", "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp", "atomicassets-contract (v2.0.0): src/atomicassets.cpp"] --- # Offers: the native two-sided trade flow -`atomicassets` offers are the contract's only built-in trade primitive: a sender proposes swapping some of their assets for some of a recipient's, the recipient accepts or declines, and either side can back out before that happens. AtomicMarket sales and buyoffers are built on top of this primitive rather than moving assets directly (sales use an offer with memo `"sale"`, buyoffers use memos `"buyoffer"` and `"tbuyoffer"`); see "How AtomicMarket sales use offers" below for how the two connect. AtomicMarket auctions are the exception: they do not use offers at all. A seller escrows the asset by a direct AtomicAssets `transfer` to the `atomicmarket` contract with the memo `"auction"`, which the contract's `receive_asset_transfer` handler picks up. Behavior here is unchanged between V1 and V2. AtomicAssets line citations below are against tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets). +`atomicassets` offers are the contract's only built-in trade primitive: a sender proposes swapping some of their assets for some of a recipient's, the recipient accepts or declines, and either side can back out before that happens. AtomicMarket sales and buyoffers are built on top of this primitive rather than moving assets directly (sales use an offer with memo `"sale"`, buyoffers use memos `"buyoffer"` and `"tbuyoffer"`); see "How AtomicMarket sales use offers" below for how the two connect. AtomicMarket auctions are the exception: they do not use offers at all. A seller escrows the asset by a direct AtomicAssets `transfer` to the `atomicmarket` contract with the memo `"auction"`, which the contract's `receive_asset_transfer` handler picks up. Behavior here is unchanged between V1 and V2. AtomicAssets line citations below are against tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets). Each action's data shape is plain JSON first, then the same call through `@wharfkit/session`'s `session.transact()`, which [Build a session and sign](signing.md) constructs. Only asset ids need the string treatment: see [AtomicMarket V2 changes](../reference/atomicmarket/v2-changes.md#large-integers-serialize-as-strings) ("Large integers serialize as strings") for why. `template_id` is an `int32_t`, and offer ids are a small contract-wide `uint64` counter (a live `offers` row reads `offer_id: 7`); both stay well inside the safe-integer range and serialize as bare JSON numbers, as the numeric `offer_id` examples below do. See [@wharfkit/antelope client behavior](../reference/wharfkit.md). @@ -47,7 +47,7 @@ await session.transact({ Ownership and transferability are checked at creation time only; they are re-checked again at `acceptoffer`, not continuously. See "What invalidates an offer" below. -Source: `atomicassets-contract src/atomicassets.cpp:1185-1273` +Source: `atomicassets-contract src/atomicassets.cpp:1188-1276` ## Accept an offer: acceptoffer @@ -76,7 +76,7 @@ Accepting re-verifies ownership of every listed asset, then runs both transfers - RAM payer: split, not uniform. Assets moving from recipient to sender use the offer's current RAM payer as the scope payer for any new scope the sender needs; assets moving from sender to recipient have the recipient cover their own new scope. In practice this means accepting an offer that requires you to hold an asset type for the first time can implicitly charge your own RAM, not the offer creator's. - Fails when: the sender or recipient no longer owns one of the listed assets (see below). -Source: `atomicassets-contract src/atomicassets.cpp:1299-1350`, `atomicassets-contract src/atomicassets.cpp:1665-1761` (`internal_transfer`, shared transfer logic) +Source: `atomicassets-contract src/atomicassets.cpp:1302-1353`, `atomicassets-contract src/atomicassets.cpp:1668-1764` (`internal_transfer`, shared transfer logic) ## Decline an offer: declineoffer @@ -99,7 +99,7 @@ await session.transact({ - RAM payer: not applicable; the row is erased and its RAM released to whoever paid for it. - Fails when: no offer with `offer_id` exists. -Source: `atomicassets-contract src/atomicassets.cpp:1358-1368` +Source: `atomicassets-contract src/atomicassets.cpp:1361-1371` ## Cancel an offer: canceloffer @@ -122,7 +122,7 @@ await session.transact({ - RAM payer: not applicable; the row is erased. - Fails when: no offer with `offer_id` exists. -Source: `atomicassets-contract src/atomicassets.cpp:1280-1290` +Source: `atomicassets-contract src/atomicassets.cpp:1283-1293` ## Reassign the RAM payer: payofferram @@ -149,7 +149,7 @@ The action erases the offer row and re-emplaces an identical copy paid for by `p - RAM payer: `payer`, after the call. - Fails when: no offer with `offer_id` exists. -Source: `atomicassets-contract src/atomicassets.cpp:1377-1395` +Source: `atomicassets-contract src/atomicassets.cpp:1380-1398` ## What invalidates an offer @@ -160,7 +160,7 @@ Source: `atomicassets-contract src/atomicassets.cpp:1377-1395` Either way, `acceptoffer` fails with `"Offer sender doesn't own at least one of the provided assets"` (or the recipient equivalent), and the offer row is left untouched, since the failed transaction makes no state changes. The contract appends the offending id to that string as a ` (ID: )` suffix (the same suffix `createoffer` and `transfer` add to their ownership and transferability errors), so a match on the message should allow for the trailing id. A stale offer is not pruned automatically: it stays in the `offers` table, discoverable by anyone reading it, until its sender calls `canceloffer`, its recipient calls `declineoffer`, or a failed `acceptoffer` prompts one of them to clean it up. Indexers and UIs that show pending offers should not assume a listed offer is still fulfillable. -Source: `atomicassets-contract src/atomicassets.cpp:1313-1325` (ownership re-check in `acceptoffer`), `atomicassets-contract src/atomicassets.cpp:1096-1177` (`burnasset` erase) +Source: `atomicassets-contract src/atomicassets.cpp:1316-1328` (ownership re-check in `acceptoffer`), `atomicassets-contract src/atomicassets.cpp:1099-1180` (`burnasset` erase) ## How AtomicMarket sales use offers diff --git a/guides/querying-the-api.md b/guides/querying-the-api.md index 93d6293..756266a 100644 --- a/guides/querying-the-api.md +++ b/guides/querying-the-api.md @@ -1,7 +1,7 @@ --- scope: Workflow patterns for reading Atomic data over the HTTP API and get_table_rows - pagination caps, state filters, chain reads, and deterministic errors depends-on: [reference/api.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp", "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp", "atomicassets-contract (v2.0.0): src/atomicassets.cpp"] --- # Query the API and chain tables diff --git a/guides/sales.md b/guides/sales.md index a6c8617..1618407 100644 --- a/guides/sales.md +++ b/guides/sales.md @@ -2,8 +2,8 @@ scope: AtomicMarket instant-sale lifecycle - announce, escrow through an AtomicAssets offer, purchase, cancel, and Delphi Oracle sales that settle in another token depends-on: [reference/atomicmarket/actions.md, reference/atomicmarket/fees-and-royalties.md, guides/offers.md] key-modules: - - "atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp" - - "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp" + - "atomicmarket-contract (v2.0.0): src/atomicmarket.cpp" + - "atomicassets-contract (v2.0.0): src/atomicassets.cpp" - "@atomichub/atomicmarket 2.4.1 (atomicmarket-sdk v2.4.1, 437300b): src/Actions/Generator.ts, src/Actions/Delphi.ts" --- diff --git a/reference/atomicassets/actions.md b/reference/atomicassets/actions.md index ec182ad..0eac571 100644 --- a/reference/atomicassets/actions.md +++ b/reference/atomicassets/actions.md @@ -1,12 +1,12 @@ --- scope: Complete action reference for the `atomicassets` contract - admin, collections, schemas, templates, assets, RAM-payer reassignment, transfers, and offers depends-on: [reference/atomicassets/structure.md, reference/atomicassets/tables.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp", "AntelopeIO/leap (v5.0.3): chain RAM-billing constants"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp", "AntelopeIO/leap (v5.0.3): chain RAM-billing constants"] --- # AtomicAssets actions -Complete action reference for the `atomicassets` contract, baselined on tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both `wax-testnet` and `jungle4-testnet`). Every entry cites its declaration in `include/atomicassets.hpp` and its body in `src/atomicassets.cpp`. "Changed in V2" notes compare against the V1 `atomicassets-contract` source. +Complete action reference for the `atomicassets` contract, baselined on tag `v2.0.0` of `atomicassets-contract` (the release pinned for both `wax-testnet` and `jungle4-testnet`). Every entry cites its declaration in `include/atomicassets.hpp` and its body in `src/atomicassets.cpp`. "Changed in V2" notes compare against the V1 `atomicassets-contract` source. Live-chain status: see [AtomicAssets V2 upgrade](v2-upgrade.md#deployment-status) ("Deployment status"). None of the V2-only actions on this page are callable on WAX mainnet yet. @@ -139,7 +139,7 @@ Required authorization: the collection's current `author`, at the `owner` permis Creates an `authorswaps` row. Fails if a swap for this collection is already underway. `acceptance_date` is set to `now` if `owner` is true (immediately acceptable), or `now + 604800` (one week out) otherwise. This is the only place the two paths diverge; `acceptauswap`'s own window is identical either way. -Source: `include/atomicassets.hpp:81-85`, `src/atomicassets.cpp:357-388` +Source: `include/atomicassets.hpp:81-85`, `src/atomicassets.cpp:357-381` ### acceptauswap @@ -147,9 +147,9 @@ Source: `include/atomicassets.hpp:81-85`, `src/atomicassets.cpp:357-388` Required authorization: the swap's `new_author`. -Reassigns `collections.author` to `new_author` and erases the `authorswaps` row. Only acceptable once `now > acceptance_date`, and only until `now < acceptance_date + 604800`. Combined with `createauswap`'s two paths, the full window measured from creation is: immediately through +7 days for an `owner`-permission swap, or +7 days through +14 days for an `active`-permission swap. (The action's own source comment claims swaps "remain valid for up to 3 weeks"; that does not match what the code computes, one or two weeks depending on path, so this page states the computed behavior rather than the comment.) +Reassigns `collections.author` to `new_author` and erases the `authorswaps` row. Acceptable from `acceptance_date` itself (the boundary second passes; the check rejects only `now < acceptance_date`), and only until `now < acceptance_date + 604800`. Combined with `createauswap`'s two paths, the full window measured from creation is: immediately through +7 days for an `owner`-permission swap, or +7 days through +14 days for an `active`-permission swap. -Source: `include/atomicassets.hpp:87-89`, `src/atomicassets.cpp:389-423` +Source: `include/atomicassets.hpp:87-89`, `src/atomicassets.cpp:390-420` ### rejectauswap @@ -159,7 +159,7 @@ Required authorization: either the swap's `current_author` or its `new_author` ( Erases the `authorswaps` row without changing `collections.author`. -Source: `include/atomicassets.hpp:91-93`, `src/atomicassets.cpp:424-449` +Source: `include/atomicassets.hpp:91-93`, `src/atomicassets.cpp:427-452` ## Schemas @@ -174,7 +174,7 @@ Required authorization: `authorized_creator`, checked via `check_has_collection_ Creates a `schemas` row scoped to `collection_name`. `schema_name` must not already exist in that scope; `schema_format` is validated by `check_format` (unique names, valid type strings, must include a `{"name": "name", "type": "string"}` line). -Source: `include/atomicassets.hpp:103-108`, `src/atomicassets.cpp:450-481` +Source: `include/atomicassets.hpp:103-108`, `src/atomicassets.cpp:453-484` ### extendschema @@ -187,7 +187,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Appends lines to an existing schema's `format` and re-validates the whole extended vector with `check_format`. Existing lines are never removed or reordered, for the same on-chain-identifier reason as `admincoledit` above; see [AtomicAssets attribute serialization](serialization.md) for why position matters. -Source: `include/atomicassets.hpp:110-115`, `src/atomicassets.cpp:482-513` +Source: `include/atomicassets.hpp:110-115`, `src/atomicassets.cpp:485-516` ### setschematyp (V2) @@ -200,7 +200,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Emplaces or fully replaces the `schematypes` row for this schema (not additive: the whole `format_type` vector passed in replaces whatever was there). Every entry's `name` must be unique in the vector and must match an existing attribute name in the schema's `format`; `mediatype` and `info` are free-form, unvalidated strings. Metadata only, never touches serialization. Changed in V2: this action and its table do not exist in V1. -Source: `include/atomicassets.hpp:117-122`, `src/atomicassets.cpp:514-565` +Source: `include/atomicassets.hpp:117-122`, `src/atomicassets.cpp:517-568` ## Templates @@ -218,7 +218,7 @@ Required authorization: `authorized_creator`, checked via `check_has_collection_ Creates a `templates` row keyed by a contract-wide `template_id` counter (`config.template_counter`, starting at 1: template ids are unique across the whole contract, not per collection). Delegates to `internal_create_template` with `mutable_data = {}`. Sends `lognewtempl`. -Source: `include/atomicassets.hpp:124-132`, `src/atomicassets.cpp:566-582`, `src/atomicassets.cpp:1613-1689` (`internal_create_template`) +Source: `include/atomicassets.hpp:124-132`, `src/atomicassets.cpp:569-585`, `src/atomicassets.cpp:1582-1658` (`internal_create_template`) ### createtempl2 (V2) @@ -230,7 +230,7 @@ Required authorization: `authorized_creator`, checked via `check_has_collection_ Identical to `createtempl`, except `internal_create_template` also receives `mutable_data`. If `mutable_data` is non-empty, it is written to a `templates2` row and a second inline action, `logsetdatatl` (with `old_data = {}`), is sent immediately after `lognewtempl`: one `createtempl2` call with non-empty mutable data produces two separate notification fan-outs in the same transaction, not one. Changed in V2: does not exist in V1, where every template's data is immutable forever after `createtempl`. -Source: `include/atomicassets.hpp:126-135`, `src/atomicassets.cpp:583-599`, `src/atomicassets.cpp:1613-1689` +Source: `include/atomicassets.hpp:126-135`, `src/atomicassets.cpp:586-602`, `src/atomicassets.cpp:1582-1658` ### settempldata (V2) @@ -243,7 +243,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Upserts the template's `templates2` row: emplaces it if absent and `new_mutable_data` is non-empty, modifies it if present and `new_mutable_data` is non-empty, and erases it if present and `new_mutable_data` is empty. A `templates2` row therefore only exists at all while the template currently has non-empty mutable data. Always sends `logsetdatatl` (with `old_data = {}` if no row existed before the call). Changed in V2: does not exist in V1. -Source: `include/atomicassets.hpp:137-142`, `src/atomicassets.cpp:846-913` +Source: `include/atomicassets.hpp:137-142`, `src/atomicassets.cpp:849-916` ### deltemplate (V2) @@ -255,7 +255,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Erases the `templates` row (and its `templates2` row, if any) only while `issued_supply == 0`. Sends no notification at all, unlike every other collection-editing action in this group: an indexer that only watches `notify_collection_accounts` fan-out will not observe a deletion, though it remains visible as the top-level action in the transaction trace. Changed in V2: does not exist in V1 (a V1 template, once created, can never be removed even with zero issued supply). -Source: `include/atomicassets.hpp:144-148`, `src/atomicassets.cpp:600-630` +Source: `include/atomicassets.hpp:144-148`, `src/atomicassets.cpp:603-633` ### locktemplate @@ -267,7 +267,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Sets `max_supply` to the current `issued_supply`, freezing further minting. Requires `issued_supply != 0` (at least one asset must already have been minted). Sends no notification. -Source: `include/atomicassets.hpp:150-154`, `src/atomicassets.cpp:631-660` +Source: `include/atomicassets.hpp:150-154`, `src/atomicassets.cpp:634-663` ### redtemplmax (V2) @@ -280,7 +280,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Lowers a template's `max_supply`. Once a finite cap has been set this way, every subsequent call must lower it further; there is no action that raises `max_supply` again. Sends no notification. Changed in V2: does not exist in V1. -Source: `include/atomicassets.hpp:156-161`, `src/atomicassets.cpp:661-696` +Source: `include/atomicassets.hpp:156-161`, `src/atomicassets.cpp:664-699` ## Assets @@ -299,7 +299,7 @@ Required authorization: `authorized_minter`, checked via `check_has_collection_a Creates an `assets` row scoped to `new_asset_owner`, keyed by a contract-wide `asset_counter` starting at 2^40 (1099511627776). If `template_id >= 0`, the template must exist, must belong to `schema_name`, and its `issued_supply` (incremented by this call) must stay within `max_supply` when `max_supply > 0`. RAM for the new row is paid by `authorized_minter`. Sends `logmint`. Changed in V2: `tokens_to_back` is checked *after* `logmint` is sent, and any non-empty value always fails with "Native backing has been deprecated on the AtomicAssets Contract": the parameter stays in the ABI for interface stability, but minting with backing no longer functions at all (in V1 it invoked `internal_back_asset` per token and actually moved deposited balance onto the new asset). -Source: `include/atomicassets.hpp:171-180`, `src/atomicassets.cpp:697-788` +Source: `include/atomicassets.hpp:171-180`, `src/atomicassets.cpp:700-791` ### setassetdata @@ -312,7 +312,7 @@ Required authorization: `authorized_editor`, checked via `check_has_collection_a Re-serializes `assets.mutable_serialized_data` and reassigns `ram_payer` to `authorized_editor`: RAM for the row moves to whoever last edited it, not the original minter or current owner. Sends `logsetdata` with the deserialized old and new data, before the row is modified. -Source: `include/atomicassets.hpp:174-179`, `src/atomicassets.cpp:796-845` +Source: `include/atomicassets.hpp:174-179`, `src/atomicassets.cpp:799-848` `setrampayer` and `setlastpayer`, the V2 actions that reassign `ram_payer` without a transfer, are documented under "RAM-payer reassignment (replaces descoped custodial rentals)" below. @@ -325,7 +325,7 @@ Required authorization: `owner`. Opens a zero-balance entry for `symbol_to_announce` in `owner`'s `balances` row (creating the row if it doesn't exist). Must be called before the first deposit of a given token symbol, so that `owner` (not the contract) pays the row's RAM. Idempotent: calling it again for an already-announced symbol returns silently rather than erroring. -Source: `include/atomicassets.hpp:192-195`, `src/atomicassets.cpp:990-1039` +Source: `include/atomicassets.hpp:192-195`, `src/atomicassets.cpp:993-1042` ### withdraw @@ -336,7 +336,7 @@ Required authorization: `owner`. Decreases `owner`'s `balances` entry for that symbol and sends a real token transfer back to `owner` from the corresponding registered contract. If the withdrawal brings that symbol's amount to exactly zero, its entry is removed from the `quantities` vector (and the whole `balances` row is erased if that was the only symbol present). A later deposit of that same symbol requires calling `announcedepo` again, even if the account's `balances` row still exists for other symbols, because the per-symbol entry itself is gone. -Source: `include/atomicassets.hpp:197-200`, `src/atomicassets.cpp:1040-1078`, `src/atomicassets.cpp:1768-1801` (`internal_decrease_balance`) +Source: `include/atomicassets.hpp:197-200`, `src/atomicassets.cpp:1043-1081`, `src/atomicassets.cpp:1771-1804` (`internal_decrease_balance`) ### backasset @@ -349,7 +349,7 @@ Required authorization: none checked; the action body is `check(false, "Native b Changed in V2: in V1 this action moved deposited balance from `payer` onto an asset's `backed_tokens` (via `internal_back_asset`). In V2 it always reverts regardless of the arguments supplied; it remains in the ABI only for interface compatibility. -Source: `include/atomicassets.hpp:202-207`, `src/atomicassets.cpp:1079-1087` +Source: `include/atomicassets.hpp:202-207`, `src/atomicassets.cpp:1082-1090` ### burnasset @@ -360,7 +360,7 @@ Required authorization: `asset_owner`. Erases the `assets` row. If the asset is templated, the template's `burnable` flag must be true. Any `backed_tokens` still on the row (only possible on assets that predate the V2 backing deprecation) are credited into `asset_owner`'s `balances` row. Sends `logburnasset` with the full pre-burn state (collection, schema, template id, backed tokens, both data layers, prior ram_payer) before erasing the row. The parent template's `issued_supply` is unchanged: the action reads the template row only for the `burnable` check, so `issued_supply` counts lifetime mints and a circulating supply must subtract burns. -Source: `include/atomicassets.hpp:209-212`, `src/atomicassets.cpp:1096-1177` +Source: `include/atomicassets.hpp:209-212`, `src/atomicassets.cpp:1099-1180` ## RAM-payer reassignment (replaces descoped custodial rentals) @@ -375,7 +375,7 @@ Required authorization: `new_payer`. Reassigns `ram_payer` on an asset the caller already owns (looked up in `new_payer`'s own scope) to `new_payer` itself. Fails if `new_payer` is already the `ram_payer`. Sends `logrampayer`. Changed in V2: does not exist in V1. -Source: `include/atomicassets.hpp:181-184`, `src/atomicassets.cpp:914-940` +Source: `include/atomicassets.hpp:181-184`, `src/atomicassets.cpp:917-943` ### setlastpayer (V2) @@ -386,7 +386,7 @@ Required authorization: `owner`. Reassigns `ram_payer` to `owner` for the single highest-`asset_id` row currently in `owner`'s scope (the multi-index's last entry by primary-key order, `--owner_assets.end()`), not necessarily the most recently acquired asset if `owner` has since reacquired an older, lower-id asset. Asserts that this asset's `collection_name` matches the passed-in `collection_name` (so the caller must know which collection they expect to be claiming for) and fails if `owner` holds no assets at all, or already pays for that asset's RAM. Sends `logrampayer`. Changed in V2: does not exist in V1. -Source: `include/atomicassets.hpp:186-189`, `src/atomicassets.cpp:943-976` +Source: `include/atomicassets.hpp:186-189`, `src/atomicassets.cpp:946-979` ### logrampayer (V2) @@ -397,7 +397,7 @@ Source: `include/atomicassets.hpp:186-189`, `src/atomicassets.cpp:943-976` Sent by `setrampayer` and `setlastpayer`. Looks up the asset's `collection_name` and calls `notify_collection_accounts`. Changed in V2: does not exist in V1; this is the notification counterpart of the V2 RAM-reassignment mechanism. -Source: `include/atomicassets.hpp:303-308`, `src/atomicassets.cpp:1535-1547` +Source: `include/atomicassets.hpp:303-308`, `src/atomicassets.cpp:1538-1550` ## Transfers and offers @@ -412,7 +412,7 @@ Required authorization: `from`. Notifies `from` and `to` directly via `require_recipient`, then calls `internal_transfer`, which: requires `to` to exist and differ from `from`; requires every asset to currently belong to `from` and, if templated, to have `transferable = true`; and, if this is the first asset `to` has ever held (an empty scope), makes `from` pay for the new scope's RAM by emplacing and immediately erasing a placeholder row (so the action fails outright if `from` cannot cover that RAM); that charge is exactly 112 bytes, the billable size the chain gives a `table_id_object`, the record that carries one table scope, and it stays with `from` while the scope exists. Sends one `logtransfer` per distinct collection touched by the batch (grouped by `std::map` key order, not caller-supplied order), each of which fans out to that collection's `notify_accounts`. -Source: `include/atomicassets.hpp:30-35`, `src/atomicassets.cpp:76-86`, `src/atomicassets.cpp:1665-1761` (`internal_transfer`); for the 112-byte figure, `AntelopeIO/leap` at `v5.0.3`: `libraries/chain/include/eosio/chain/config.hpp:108,140,146` and `libraries/chain/include/eosio/chain/contract_table_objects.hpp:244-247` (`billable_size_v` = align_up(44 + 2x32, 16) = 112), charged at `libraries/chain/apply_context.cpp:691`; live WAX mainnet read via `wax.greymass.com` `POST /v1/history/get_transaction`, tx `1ec40244151f86b361f9fa18de6ed7bb1413608792141538e0de531a53c55393`, whose `account_ram_deltas` bill the sender exactly +112 +Source: `include/atomicassets.hpp:30-35`, `src/atomicassets.cpp:76-86`, `src/atomicassets.cpp:1668-1764` (`internal_transfer`); for the 112-byte figure, `AntelopeIO/leap` at `v5.0.3`: `libraries/chain/include/eosio/chain/config.hpp:108,140,146` and `libraries/chain/include/eosio/chain/contract_table_objects.hpp:244-247` (`billable_size_v` = align_up(44 + 2x32, 16) = 112), charged at `libraries/chain/apply_context.cpp:691`; live WAX mainnet read via `wax.greymass.com` `POST /v1/history/get_transaction`, tx `1ec40244151f86b361f9fa18de6ed7bb1413608792141538e0de531a53c55393`, whose `account_ram_deltas` bill the sender exactly +112 ### createoffer @@ -426,7 +426,7 @@ Required authorization: `sender`. Creates an `offers` row keyed by a global `offer_counter`. Every listed asset must currently belong to the side it's listed under and, if templated, be `transferable`. Sends `lognewoffer`, which notifies `sender` and `recipient` directly. -Source: `include/atomicassets.hpp:215-221`, `src/atomicassets.cpp:1185-1279` +Source: `include/atomicassets.hpp:215-221`, `src/atomicassets.cpp:1188-1282` ### canceloffer @@ -436,7 +436,7 @@ Required authorization: the offer's `sender` only (not the `recipient`). Erases the offer row. Sends no notification of any kind, to either party. -Source: `include/atomicassets.hpp:223-225`, `src/atomicassets.cpp:1280-1298` +Source: `include/atomicassets.hpp:223-225`, `src/atomicassets.cpp:1283-1301` ### acceptoffer @@ -446,7 +446,7 @@ Required authorization: the offer's `recipient` only. Notifies `sender` and `recipient` directly via `require_recipient` (not through a log action), then executes both legs through `internal_transfer`: `recipient`'s listed assets move to `sender` with `sender` (specifically the offer's own `ram_payer`, which may have been reassigned by `payofferram`) covering any new-scope RAM, and `sender`'s listed assets move to `recipient` with `recipient` covering any new-scope RAM. Erases the offer row. Each leg's `internal_transfer` call still sends its own per-collection `logtransfer` actions. -Source: `include/atomicassets.hpp:227-229`, `src/atomicassets.cpp:1299-1357` +Source: `include/atomicassets.hpp:227-229`, `src/atomicassets.cpp:1302-1360` ### declineoffer @@ -456,7 +456,7 @@ Required authorization: the offer's `recipient` only. Erases the offer row. Sends no notification of any kind. -Source: `include/atomicassets.hpp:231-233`, `src/atomicassets.cpp:1358-1376` +Source: `include/atomicassets.hpp:231-233`, `src/atomicassets.cpp:1361-1379` ### payofferram @@ -467,7 +467,7 @@ Required authorization: `payer` only (no relationship to the offer's `sender` or Erases the offer row and re-emplaces an identical copy with `ram_payer` set to `payer`, moving the row's RAM bill to `payer` without touching any of its other fields. Intended for a dapp to sponsor the RAM of offers its users create. Sends no notification. -Source: `include/atomicassets.hpp:235-238`, `src/atomicassets.cpp:1377-1401` +Source: `include/atomicassets.hpp:235-238`, `src/atomicassets.cpp:1380-1404` ## Token deposit notification handler @@ -482,7 +482,7 @@ Not a regular action: declared `[[eosio::on_notify("*::transfer")]]`, so it runs Returns immediately if `to != get_self()`. Otherwise requires the `(get_first_receiver(), quantity.symbol)` pair to match an entry in `config.supported_tokens` (the check matches the full contract-and-symbol pair; the symbol alone is not enough), requires `memo` to be exactly the literal string `"deposit"` (anything else, including an empty memo, fails the whole incoming transfer), and requires `from` to already have an `announcedepo`'d `balances` entry for that exact symbol. On success, credits the deposited amount into that entry. -Source: `include/atomicassets.hpp:238-243`, `src/atomicassets.cpp:1402-1444` +Source: `include/atomicassets.hpp:238-243`, `src/atomicassets.cpp:1405-1447` ## Notification actions (contract-internal) @@ -498,7 +498,7 @@ Every action in this group requires `require_auth(get_self())`: they can only ru Sent by `internal_transfer` (used by both `transfer` and `acceptoffer`), once per distinct collection in the batch. Calls `notify_collection_accounts(collection_name)`. -Source: `include/atomicassets.hpp:247-253`, `src/atomicassets.cpp:1445-1456` +Source: `include/atomicassets.hpp:247-253`, `src/atomicassets.cpp:1448-1459` ### lognewoffer @@ -511,7 +511,7 @@ Source: `include/atomicassets.hpp:247-253`, `src/atomicassets.cpp:1445-1456` Sent by `createoffer`. Calls `require_recipient(sender)` and `require_recipient(recipient)`. -Source: `include/atomicassets.hpp:255-262`, `src/atomicassets.cpp:1457-1471` +Source: `include/atomicassets.hpp:255-262`, `src/atomicassets.cpp:1460-1474` ### lognewtempl @@ -526,7 +526,7 @@ Source: `include/atomicassets.hpp:255-262`, `src/atomicassets.cpp:1457-1471` Sent by `internal_create_template` (used by both `createtempl` and `createtempl2`). Calls `notify_collection_accounts(collection_name)`. -Source: `include/atomicassets.hpp:264-273`, `src/atomicassets.cpp:1472-1487` +Source: `include/atomicassets.hpp:264-273`, `src/atomicassets.cpp:1475-1490` ### logmint @@ -543,7 +543,7 @@ Source: `include/atomicassets.hpp:264-273`, `src/atomicassets.cpp:1472-1487` Sent by `mintasset`. Calls `require_recipient(new_asset_owner)` and `notify_collection_accounts(collection_name)`. -Source: `include/atomicassets.hpp:275-286`, `src/atomicassets.cpp:1488-1507` +Source: `include/atomicassets.hpp:275-286`, `src/atomicassets.cpp:1491-1510` ### logsetdata @@ -554,7 +554,7 @@ Source: `include/atomicassets.hpp:275-286`, `src/atomicassets.cpp:1488-1507` Sent by `setassetdata`. Looks up the asset's `collection_name` (by `asset_owner`/`asset_id`) and calls `notify_collection_accounts`; no direct `require_recipient(asset_owner)`. -Source: `include/atomicassets.hpp:288-293`, `src/atomicassets.cpp:1508-1521` +Source: `include/atomicassets.hpp:288-293`, `src/atomicassets.cpp:1511-1524` ### logsetdatatl (V2) @@ -566,7 +566,7 @@ Source: `include/atomicassets.hpp:288-293`, `src/atomicassets.cpp:1508-1521` Sent by `createtempl2` (when given non-empty mutable data) and `settempldata`. Calls `notify_collection_accounts(collection_name)`. Changed in V2: does not exist in V1. -Source: `include/atomicassets.hpp:295-301`, `src/atomicassets.cpp:1522-1534` +Source: `include/atomicassets.hpp:295-301`, `src/atomicassets.cpp:1525-1537` `logrampayer`, sent by `setrampayer` and `setlastpayer`, is documented under "RAM-payer reassignment (replaces descoped custodial rentals)" below rather than in this group. @@ -578,7 +578,7 @@ Source: `include/atomicassets.hpp:295-301`, `src/atomicassets.cpp:1522-1534` Body is `require_auth(get_self())` only; no notification of any kind is sent. Changed in V2: in V1 this action called `require_recipient(asset_owner)` and `notify_collection_accounts`. In V2 it is dead code kept only for ABI compatibility: `backasset` always reverts and `mintasset`'s backing path always reverts, so nothing in the shipped contract ever dispatches this action. -Source: `include/atomicassets.hpp:310-314`, `src/atomicassets.cpp:1550-1557` +Source: `include/atomicassets.hpp:310-314`, `src/atomicassets.cpp:1553-1560` ### logburnasset @@ -594,4 +594,4 @@ Source: `include/atomicassets.hpp:310-314`, `src/atomicassets.cpp:1550-1557` Sent by `burnasset`. Calls `notify_collection_accounts(collection_name)`. -Source: `include/atomicassets.hpp:316-326`, `src/atomicassets.cpp:1559-1578` +Source: `include/atomicassets.hpp:316-326`, `src/atomicassets.cpp:1562-1581` diff --git a/reference/atomicassets/backing-tokens.md b/reference/atomicassets/backing-tokens.md index 861d865..3e37187 100644 --- a/reference/atomicassets/backing-tokens.md +++ b/reference/atomicassets/backing-tokens.md @@ -1,24 +1,24 @@ --- scope: The `atomicassets` fungible-token backing mechanism - announcing a deposit, where backed value is stored, recovery through burnasset, and its V2 deprecation depends-on: [reference/atomicassets/structure.md, reference/atomicassets/actions.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets backing tokens -The `atomicassets` contract's fungible-token backing mechanism: the deposit-then-spend pattern, where backed value is stored, how it was recovered, and the RAM-payer consequence of backing an asset. Baseline is the V2 contract, tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets); the single most material V2 change is that backing is now deprecated, covered below. +The `atomicassets` contract's fungible-token backing mechanism: the deposit-then-spend pattern, where backed value is stored, how it was recovered, and the RAM-payer consequence of backing an asset. Baseline is the V2 contract, tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets); the single most material V2 change is that backing is now deprecated, covered below. ## Depositing tokens before backing The contract never treats an arbitrary incoming token transfer as a backing instruction. `announcedepo` creates (or extends) an owner's `balances` row with a zero-value placeholder for one whitelisted symbol, paid for by the announcing account. A subsequent token transfer to the contract carrying memo `"deposit"` is only accepted if a placeholder for that exact symbol already exists in `balances`; it is credited by adding the transferred amount to that entry. Any other memo, or a token contract/symbol pair not in the `config` singleton's `supported_tokens` list (populated only by the contract-authority action `addconftoken`), makes the incoming transfer fail. The two-step shape exists so the depositor, not the contract, pays for the RAM of their own `balances` row. -Source: `src/atomicassets.cpp:990-1032` (announcedepo), `src/atomicassets.cpp:1402-1442` (receive_token_transfer), `src/atomicassets.cpp:56-69` (addconftoken), `include/atomicassets.hpp:240` (on_notify declaration), `include/atomicassets.hpp:445-451` (`balances_s`) +Source: `src/atomicassets.cpp:993-1035` (announcedepo), `src/atomicassets.cpp:1405-1445` (receive_token_transfer), `src/atomicassets.cpp:56-69` (addconftoken), `include/atomicassets.hpp:240` (on_notify declaration), `include/atomicassets.hpp:445-451` (`balances_s`) ## The balances table is a general-purpose deposit ledger `balances_s` is one row per owner holding a vector of `asset` quantities, one entry per announced symbol, with no link to any specific asset. `withdraw` spends directly out of this pool back to the owner's account through the token contract recorded in `supported_tokens`. Historically `backasset` spent out of the same pool to attach value to an asset. The table itself is not backing-specific; it is whatever pre-funded balance any contract action needs. -Source: `include/atomicassets.hpp:445-451` (`balances_s`), `src/atomicassets.cpp:1040-1070` (withdraw), `src/atomicassets.cpp:1768-1801` (internal_decrease_balance) +Source: `include/atomicassets.hpp:445-451` (`balances_s`), `src/atomicassets.cpp:1043-1073` (withdraw), `src/atomicassets.cpp:1771-1804` (internal_decrease_balance) ## How backing worked: burnable-only, and the RAM payer moves @@ -36,13 +36,13 @@ Source: `include/atomicassets.hpp:409-421` (`assets_s`) The only action that ever removes value from `backed_tokens` is `burnasset`, and only as a side effect of destroying the asset. If `backed_tokens` is non-empty, `burnasset` moves the full vector into the owner's `balances` row (creating one if none exists, merging into existing per-symbol amounts otherwise), then erases the asset. There is no action to unback an asset while it stays alive and no partial-withdraw path; only the current `asset_owner`, who must sign `burnasset`, can trigger it. This action's shape is unchanged between V1 and the current V2 source. -Source: `src/atomicassets.cpp:1096-1177` (burnasset) +Source: `src/atomicassets.cpp:1099-1180` (burnasset) ## Changed in V2: native backing is deprecated The current V2 contract source disables new backing outright. `backasset` unconditionally aborts with "Native backing has been deprecated on the AtomicAssets Contract," and `mintasset`'s `tokens_to_back` parameter is only accepted if empty, aborting with the same message otherwise. `announcedepo`, the deposit-transfer flow, and `withdraw` are untouched, so the deposit ledger still works as a generic pre-funded balance; it simply can never be spent into an asset's `backed_tokens` again. `burnasset`'s recovery path is untouched and stays live: any asset that was backed before the deprecation still releases its `backed_tokens` to the owner's balance when burned. `logbackasset` remains declared in the V2 ABI as an empty stub, kept only for backwards ABI compatibility; nothing invokes it once backing is disabled, so a contract watching for it will not see one again on a chain running this V2 build. -Source: `src/atomicassets.cpp:786-787` (mintasset abort), `src/atomicassets.cpp:1085-1086` (backasset abort), `src/atomicassets.cpp:1550-1556` (logbackasset stub) +Source: `src/atomicassets.cpp:789-790` (mintasset abort), `src/atomicassets.cpp:1088-1089` (backasset abort), `src/atomicassets.cpp:1553-1559` (logbackasset stub) ## Live-chain status diff --git a/reference/atomicassets/custom-types.md b/reference/atomicassets/custom-types.md index 0985b15..eaacb66 100644 --- a/reference/atomicassets/custom-types.md +++ b/reference/atomicassets/custom-types.md @@ -1,12 +1,12 @@ --- scope: The ABI/C++ type system the `atomicassets` contract uses to describe and carry attribute data - FORMAT, ATOMIC_ATTRIBUTE, ATTRIBUTE_MAP, and FORMAT_TYPE depends-on: [reference/atomicassets/serialization.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets attribute type system -The ABI/C++ types the `atomicassets` contract uses to describe and carry attribute data: the `FORMAT` schema-line struct, the `ATOMIC_ATTRIBUTE` variant, the `ATTRIBUTE_MAP` map type, and the V2-only `FORMAT_TYPE` metadata struct. This document covers the type system and its ABI/JSON representation; the byte-level encoding those types eventually produce is covered in [AtomicAssets attribute serialization](serialization.md), which is the file to read for wire format, not this one. Raw-vs-patched ABI mechanics are covered in [Contract releases and deployment](../contract-releases.md); this file only notes where that concern touches these specific types. Full table shapes and scoping for `schemas`/`schematypes`/`templates`/`assets` are covered in [AtomicAssets data model structure](structure.md); this file focuses on the `FORMAT`/`FORMAT_TYPE`/`ATOMIC_ATTRIBUTE`/`ATTRIBUTE_MAP` types themselves. Contract citations below are against tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets). +The ABI/C++ types the `atomicassets` contract uses to describe and carry attribute data: the `FORMAT` schema-line struct, the `ATOMIC_ATTRIBUTE` variant, the `ATTRIBUTE_MAP` map type, and the V2-only `FORMAT_TYPE` metadata struct. This document covers the type system and its ABI/JSON representation; the byte-level encoding those types eventually produce is covered in [AtomicAssets attribute serialization](serialization.md), which is the file to read for wire format, not this one. Raw-vs-patched ABI mechanics are covered in [Contract releases and deployment](../contract-releases.md); this file only notes where that concern touches these specific types. Full table shapes and scoping for `schemas`/`schematypes`/`templates`/`assets` are covered in [AtomicAssets data model structure](structure.md); this file focuses on the `FORMAT`/`FORMAT_TYPE`/`ATOMIC_ATTRIBUTE`/`ATTRIBUTE_MAP` types themselves. Contract citations below are against tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets). ## FORMAT declares one attribute's name and wire type @@ -19,7 +19,7 @@ struct FORMAT { A schema is a `vector`, one line per attribute, and the position of a line in that vector is itself meaningful (see [AtomicAssets attribute serialization](serialization.md)). `check_format` enforces three rules on a candidate `vector`: every `name` is non-empty and at most 64 characters; every `type` matches one of the allowed type strings below; no two lines share a `name`; and at least one line must be exactly `{"name": "name", "type": "string"}`. That last rule is a distinct 64-character limit from `check_name_length`, which instead caps the *value* stored under an attribute literally named `name`, in every schema that defines one, rather than only the schema's own required `name` line. The two checks share a number but apply to different things: one to the schema's declared attribute-name string, the other to the data's `name`-valued string at write time. -Source: `include/atomicdata.hpp:35-38` (struct), `include/checkformat.hpp:32-97` (`check_format`), `include/checkformat.hpp:43-44` (name length), `include/checkformat.hpp:95-96` (required `name` line), `src/atomicassets.cpp:1895-1905` (`check_name_length`) +Source: `include/atomicdata.hpp:35-38` (struct), `include/checkformat.hpp:32-97` (`check_format`), `include/checkformat.hpp:43-44` (name length), `include/checkformat.hpp:95-96` (required `name` line), `src/atomicassets.cpp:1898-1908` (`check_name_length`) ## Allowed format type strings @@ -82,4 +82,4 @@ struct FORMAT_TYPE { `FORMAT_TYPE` and its action `setschematyp` do not exist in the V1 contract source at all. In V2, `setschematyp` writes a `vector` into a schema-scoped `schematypes` table, keyed by `schema_name` alongside the existing `schemas` table. The contract enforces only two rules on `schema_format_type`: names must be unique within the vector, and every `name` must match an existing `FORMAT.name` in that schema. `mediatype` and `info` are free-form strings with no contract-side validation. Per the action's own comment, this exists to describe a schema attribute (for example labeling what a "Rarity" attribute means) or to tag a media type for an IPFS-backed attribute (for example marking a hash as a `.glb` or `.png` file) for downstream tooling to interpret. `FORMAT_TYPE` rows never pass through `atomicdata::serialize`/`deserialize`. They are plain ABI-serialized table rows, not custom-binary-encoded `vector` blobs, so `reference/atomicassets/serialization.md`'s codec has no bearing on them at all. -Source: `include/atomicdata.hpp:40-44` (struct, present in V2 only), `include/atomicassets.hpp:109-114` (`setschematyp` action declaration), `include/atomicassets.hpp:373-379` (`schema_types_s` / `schematypes` table), `src/atomicassets.cpp:514-560` (`setschematyp` implementation and its validation rules); confirmed absent from the V1 contract source tree (`include/atomicassets.hpp`, `include/atomicassets-interface.hpp`, `src/atomicassets.cpp`) +Source: `include/atomicdata.hpp:40-44` (struct, present in V2 only), `include/atomicassets.hpp:109-114` (`setschematyp` action declaration), `include/atomicassets.hpp:373-379` (`schema_types_s` / `schematypes` table), `src/atomicassets.cpp:517-563` (`setschematyp` implementation and its validation rules); confirmed absent from the V1 contract source tree (`include/atomicassets.hpp`, `include/atomicassets-interface.hpp`, `src/atomicassets.cpp`) diff --git a/reference/atomicassets/data-precedence.md b/reference/atomicassets/data-precedence.md index dfb5afc..7bdf5a9 100644 --- a/reference/atomicassets/data-precedence.md +++ b/reference/atomicassets/data-precedence.md @@ -1,12 +1,12 @@ --- scope: How the template and asset data layers combine into an asset's effective attributes, which layer wins a name collision, and what a reader has to do depends-on: [reference/atomicassets/structure.md, reference/atomicassets/serialization.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # Attribute data precedence -An asset's displayed attributes can come from up to three separate storage locations that all serialize against the same schema: the template's immutable data, the asset's own immutable data, and the asset's mutable data. The contract never merges these on-chain - every table stores its own layer as raw serialized bytes, and it is up to whatever reads the chain (an indexer, an API, a client library) to deserialize each layer and combine them into one effective attribute set. When more than one layer defines the same attribute name, the layers do not average or concatenate: one layer's value wins outright. (V2 adds a fourth layer, template mutable data; see "Changed in V2" below.) Contract citations below are against tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets). +An asset's displayed attributes can come from up to three separate storage locations that all serialize against the same schema: the template's immutable data, the asset's own immutable data, and the asset's mutable data. The contract never merges these on-chain - every table stores its own layer as raw serialized bytes, and it is up to whatever reads the chain (an indexer, an API, a client library) to deserialize each layer and combine them into one effective attribute set. When more than one layer defines the same attribute name, the layers do not average or concatenate: one layer's value wins outright. (V2 adds a fourth layer, template mutable data; see "Changed in V2" below.) Contract citations below are against tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets). ## Where each layer lives @@ -16,7 +16,7 @@ An asset's displayed attributes can come from up to three separate storage locat Changed in V2: a fourth layer. `template_mutables` (contract table `templates2`), scoped by `collection_name` and keyed by `template_id`, holds a `mutable_serialized_data` for the template itself, set via `createtempl2` or changed via `settempldata`. A V1 integrator's mental model of "templates are always fully immutable" no longer holds in V2: two different assets referencing the same template can see that template's mutable attributes change together, independent of anything at the asset level. This layer only exists as a table row once non-empty data has been set for that template. -Source: `src/atomicassets.cpp:697-788` (mintasset writes both asset layers), `src/atomicassets.cpp:796-836` (setassetdata rewrites only the mutable layer), `src/atomicassets.cpp:1579-1655` (internal_create_template writes the template immutable layer and, if given non-empty data, the template mutable layer), `src/atomicassets.cpp:846-907` (settempldata is the only action that changes template mutable data later) +Source: `src/atomicassets.cpp:700-791` (mintasset writes both asset layers), `src/atomicassets.cpp:799-839` (setassetdata rewrites only the mutable layer), `src/atomicassets.cpp:1582-1658` (internal_create_template writes the template immutable layer and, if given non-empty data, the template mutable layer), `src/atomicassets.cpp:849-910` (settempldata is the only action that changes template mutable data later) ## Serialization: identifiers are positions, not names @@ -54,4 +54,4 @@ To compute an asset's effective attributes from scratch: 4. Merge in this order, letting each later step override matching keys: template mutable data, then asset mutable data, then asset immutable data, then template immutable data. That is the order the `atomicassets-api` reference reader uses (template mutable at the bottom, template immutable at the top). The contract prescribes no order of its own, so a reader with a different use case is free to place the template mutable layer elsewhere; this order simply matches the reference implementation. 5. Treat a key absent from all fetched layers as unset, not as an empty string or zero - the serialization format never encodes "no value" as anything other than the key's absence. -Source: derived from `src/atomicassets.cpp:697-788`, `src/atomicassets.cpp:796-836`, `src/atomicassets.cpp:846-907`, `src/atomicassets.cpp:1579-1655`, `include/atomicdata.hpp:488-524`, cross-checked against `atomicassets-api src/api/namespaces/atomicassets/format.ts:1-36` +Source: derived from `src/atomicassets.cpp:700-791`, `src/atomicassets.cpp:799-839`, `src/atomicassets.cpp:849-910`, `src/atomicassets.cpp:1582-1658`, `include/atomicdata.hpp:488-524`, cross-checked against `atomicassets-api src/api/namespaces/atomicassets/format.ts:1-36` diff --git a/reference/atomicassets/notifications.md b/reference/atomicassets/notifications.md index 77ecd53..1bff0fc 100644 --- a/reference/atomicassets/notifications.md +++ b/reference/atomicassets/notifications.md @@ -1,12 +1,12 @@ --- scope: How `atomicassets` notifies collections and parties via require_recipient and notify_collection_accounts, and what a notified contract can and cannot assume depends-on: [reference/atomicassets/structure.md, reference/atomicassets/actions.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets notifications -How a collection opts a smart contract into `require_recipient` notifications, which actions notify which parties, and what a notified contract can and cannot assume. Baseline is the V2 contract, tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets); differences from V1 are called out under "Changed in V2." +How a collection opts a smart contract into `require_recipient` notifications, which actions notify which parties, and what a notified contract can and cannot assume. Baseline is the V2 contract, tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets); differences from V1 are called out under "Changed in V2." ## Collection notify accounts @@ -39,20 +39,20 @@ Two distinct mechanisms exist. Some actions call `require_recipient` directly on | `burnasset` (via `logburnasset`) | the collection's `notify_accounts` | `notify_collection_accounts` only | | `backasset` (V1, via `logbackasset`) | `asset_owner`, plus the collection's `notify_accounts` | `require_recipient` and `notify_collection_accounts` together; unreachable in V2, where `logbackasset` is an empty stub (see `reference/atomicassets/backing-tokens.md`) | -Source: `src/atomicassets.cpp:76-86` (transfer), `src/atomicassets.cpp:1185-1273` (createoffer), `src/atomicassets.cpp:1457-1469` (lognewoffer), `src/atomicassets.cpp:1299-1350` (acceptoffer), `src/atomicassets.cpp:1280-1290` (canceloffer), `src/atomicassets.cpp:1358-1368` (declineoffer), `src/atomicassets.cpp:697-788` (mintasset), `src/atomicassets.cpp:796-836` (setassetdata), `src/atomicassets.cpp:846-907` (settempldata), `src/atomicassets.cpp:914-976` (setrampayer/setlastpayer), `src/atomicassets.cpp:1096-1177` (burnasset), `src/atomicassets.cpp:1445-1573` (log action bodies), `src/atomicassets.cpp:1665-1761` (internal_transfer) +Source: `src/atomicassets.cpp:76-86` (transfer), `src/atomicassets.cpp:1188-1276` (createoffer), `src/atomicassets.cpp:1460-1472` (lognewoffer), `src/atomicassets.cpp:1302-1353` (acceptoffer), `src/atomicassets.cpp:1283-1293` (canceloffer), `src/atomicassets.cpp:1361-1371` (declineoffer), `src/atomicassets.cpp:700-791` (mintasset), `src/atomicassets.cpp:799-839` (setassetdata), `src/atomicassets.cpp:849-910` (settempldata), `src/atomicassets.cpp:917-979` (setrampayer/setlastpayer), `src/atomicassets.cpp:1099-1180` (burnasset), `src/atomicassets.cpp:1448-1576` (log action bodies), `src/atomicassets.cpp:1668-1764` (internal_transfer) ## What a notified contract can and cannot rely on A notification is delivered inline, in the same transaction as the triggering action: a notified contract's own handler runs as part of that transaction and can abort it by throwing, so being on a `notify_accounts` list is a way to gate or observe an action, not a read-only subscription. What arrives is only the notifying action's own parameters (for example `logsetdata` carries the deserialized old and new mutable data); a notified contract that needs anything beyond that has to query the tables itself. The set of accounts notified for a collection is read fresh at the moment the `log*` action runs, not cached from an earlier point in the transaction. Two things a notified contract cannot assume: it will not hear anything about `canceloffer` or `declineoffer`, since neither sends any notification, and grouping of a multi-asset `transfer` into per-collection `logtransfer` calls follows `std::map` key order, not the order the caller supplied asset ids in. -Source: `src/atomicassets.cpp:1823-1856` (`partial_read_collection`), `src/atomicassets.cpp:1880-1888` (`notify_collection_accounts`), `src/atomicassets.cpp:1665-1761` (internal_transfer collection grouping) +Source: `src/atomicassets.cpp:1826-1859` (`partial_read_collection`), `src/atomicassets.cpp:1883-1891` (`notify_collection_accounts`), `src/atomicassets.cpp:1668-1764` (internal_transfer collection grouping) ## Changed in V2 Two notification points are new. `setrampayer` and `setlastpayer` each send the inline `logrampayer` action, which notifies the affected asset's collection `notify_accounts` through `notify_collection_accounts` (there is no direct `require_recipient` on the owner); see [AtomicAssets actions](actions.md#ram-payer-reassignment-replaces-descoped-custodial-rentals) ("RAM-payer reassignment (replaces descoped custodial rentals)") for the mechanism and the abandoned design it replaced. `settempldata`/`logsetdatatl` is new alongside V2's mutable-template-data feature and notifies only the collection's `notify_accounts`, with no per-account recipient. Separately, `addnotifyacc`'s 24-account cap is new in V2 (see [AtomicAssets data model structure](structure.md#authorization-and-the-24-account-cap), "Authorization and the 24-account cap"). Finally, `logbackasset`'s V1 notification behavior (`require_recipient(asset_owner)` plus `notify_collection_accounts`) is now dead code: the V2 `logbackasset` action body is an empty stub kept only for ABI compatibility, and nothing in V2 ever sends it, because `backasset` and `mintasset`'s backing path both abort before reaching a log call. -Source: `src/atomicassets.cpp:914-940` (setrampayer), `src/atomicassets.cpp:943-976` (setlastpayer), `src/atomicassets.cpp:1535-1547` (logrampayer), `src/atomicassets.cpp:846-907` (settempldata), `src/atomicassets.cpp:1522-1532` (logsetdatatl), `src/atomicassets.cpp:274` (24-account cap in addnotifyacc), `src/atomicassets.cpp:1550-1556` (V2 logbackasset stub); V1 backing/notification behavior lives in this repo's V1 tree (`contracts/atomicassets-contract`) +Source: `src/atomicassets.cpp:917-943` (setrampayer), `src/atomicassets.cpp:946-979` (setlastpayer), `src/atomicassets.cpp:1538-1550` (logrampayer), `src/atomicassets.cpp:849-910` (settempldata), `src/atomicassets.cpp:1525-1535` (logsetdatatl), `src/atomicassets.cpp:274` (24-account cap in addnotifyacc), `src/atomicassets.cpp:1553-1559` (V2 logbackasset stub); V1 backing/notification behavior lives in this repo's V1 tree (`contracts/atomicassets-contract`) ## Live-chain status -See [AtomicAssets V2 upgrade](v2-upgrade.md#deployment-status) ("Deployment status"). Every V2-only notification point above is source-verified against the `v2.0.0-rc4` contract but had not shipped to WAX mainnet at the time of this check. +See [AtomicAssets V2 upgrade](v2-upgrade.md#deployment-status) ("Deployment status"). Every V2-only notification point above is source-verified against the `v2.0.0` contract but had not shipped to WAX mainnet at the time of this check. diff --git a/reference/atomicassets/serialization.md b/reference/atomicassets/serialization.md index ad137ee..f7357a2 100644 --- a/reference/atomicassets/serialization.md +++ b/reference/atomicassets/serialization.md @@ -1,12 +1,12 @@ --- scope: The custom binary format the `atomicassets` contract uses to encode attribute data - varints, zigzag, per-type wire encoding, arrays, and identifiers depends-on: [reference/atomicassets/structure.md, reference/atomicassets/custom-types.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets attribute serialization -The custom binary format the `atomicassets` contract uses to store attribute data (collection data, and template/asset immutable and mutable data) as `vector` table fields instead of raw ABI structs. The format is schema-driven: encoding and decoding both require the same ordered `FORMAT` list (see [AtomicAssets attribute type system](custom-types.md)) that produced the bytes. Baseline is the V2 contract, tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets); the encoding logic is unchanged from V1 (see "Changed in V2" below). +The custom binary format the `atomicassets` contract uses to store attribute data (collection data, and template/asset immutable and mutable data) as `vector` table fields instead of raw ABI structs. The format is schema-driven: encoding and decoding both require the same ordered `FORMAT` list (see [AtomicAssets attribute type system](custom-types.md)) that produced the bytes. Baseline is the V2 contract, tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets); the encoding logic is unchanged from V1 (see "Changed in V2" below). ## The format trades a schema lookup for RAM @@ -14,7 +14,7 @@ Storing attribute data as ABI-serialized structs would repeat each attribute's n The same codec also serializes collection data, using a single contract-wide `FORMAT` list stored in the `config` table (`collection_format`, extended only by `admincoledit`) instead of a per-schema one. -Source: `include/atomicdata.hpp:488-524`, `src/atomicassets.cpp:18-31` (`admincoledit`), `src/atomicassets.cpp:156,182` (collection data via `config.collection_format`), `src/atomicassets.cpp:763-764,834,1617,1644` (template/asset data via `schema.format`) +Source: `include/atomicdata.hpp:488-524`, `src/atomicassets.cpp:18-31` (`admincoledit`), `src/atomicassets.cpp:156,182` (collection data via `config.collection_format`), `src/atomicassets.cpp:766-767,834,1617,1644` (template/asset data via `schema.format`) ## Varints compress small numbers into few bytes @@ -58,7 +58,7 @@ Source: `include/atomicdata.hpp:122-238` (serialize array branch), `include/atom `serialize` walks the schema's `FORMAT` list in order, and for each attribute present in the supplied `ATTRIBUTE_MAP` writes a varint-encoded identifier equal to `(position in the FORMAT list) + RESERVED`, where `RESERVED` is the constant `4`, followed by that attribute's encoded value. Attributes absent from the map are simply skipped (no placeholder byte). `deserialize` reads a stream of `(identifier, value)` pairs until it runs out of bytes, and looks up `format_lines.at(identifier - RESERVED)` to know which type to decode next and which name to attach the result to. Because the identifier is a position in the `FORMAT` list rather than a hash or name, extending a schema (`extendschema`) or the collection format (`admincoledit`) only ever appends new lines: inserting or reordering existing lines would silently repoint every previously stored identifier at a different attribute. Both extension actions insert only at the end of the existing list before re-running `check_format` on the result. -Source: `include/atomicdata.hpp:46`, `include/atomicdata.hpp:488-524`, `src/atomicassets.cpp:482-506` (`extendschema` appends), `src/atomicassets.cpp:18-34` (`admincoledit` appends) +Source: `include/atomicdata.hpp:46`, `include/atomicdata.hpp:488-524`, `src/atomicassets.cpp:485-509` (`extendschema` appends), `src/atomicassets.cpp:18-34` (`admincoledit` appends) ## Serializing and deserializing off-chain diff --git a/reference/atomicassets/structure.md b/reference/atomicassets/structure.md index a6667f6..2d3ec00 100644 --- a/reference/atomicassets/structure.md +++ b/reference/atomicassets/structure.md @@ -1,12 +1,12 @@ --- scope: The AtomicAssets data model - collections, schemas, templates, and assets - the authorization model governing them, and how each table is scoped depends-on: [] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets data model structure -The `atomicassets` contract organizes assets in four levels: collections group schemas and templates and hold the authorization rules, schemas declare the attribute formats a collection's data serializes to, templates carry immutable data shared by many assets, and assets are the individual items an account owns. Baseline behavior below is V2, tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both testnets: `include/atomicassets.hpp`, `src/atomicassets.cpp`); "Changed in V2" notes call out where V1 differs enough to matter to an integrator. +The `atomicassets` contract organizes assets in four levels: collections group schemas and templates and hold the authorization rules, schemas declare the attribute formats a collection's data serializes to, templates carry immutable data shared by many assets, and assets are the individual items an account owns. Baseline behavior below is V2, tag `v2.0.0` of `atomicassets-contract` (the release pinned for both testnets: `include/atomicassets.hpp`, `src/atomicassets.cpp`); "Changed in V2" notes call out where V1 differs enough to matter to an integrator. ```mermaid flowchart TD @@ -48,7 +48,7 @@ Schemas can only be extended, never edited retroactively: `extendschema` appends Changed in V2: schema type descriptors. The `schema_types` table (`setschematyp` action) attaches an optional `FORMAT_TYPE { name, mediatype, info }` per attribute - a human-readable description and, for binary-carrying types, a media type hint (for example marking an `ipfs` attribute as a `.glb` 3D model). It is metadata only: it does not affect serialization and every named attribute must already exist in the schema's `format`. V1 has no equivalent table. -Source: `include/atomicdata.hpp:35-44` (`FORMAT`, `FORMAT_TYPE`), `include/checkformat.hpp:32-97` (`check_format`), `include/checkformat.hpp:95-96` (mandatory name/string line), `include/checkformat.hpp:89-90` (uniqueness), `include/atomicassets.hpp:363-379` (schemas and schema_types tables), `src/atomicassets.cpp:450-475` (createschema), `src/atomicassets.cpp:482-506` (extendschema, append-only), `src/atomicassets.cpp:514-560` (setschematyp) +Source: `include/atomicdata.hpp:35-44` (`FORMAT`, `FORMAT_TYPE`), `include/checkformat.hpp:32-97` (`check_format`), `include/checkformat.hpp:95-96` (mandatory name/string line), `include/checkformat.hpp:89-90` (uniqueness), `include/atomicassets.hpp:363-379` (schemas and schema_types tables), `src/atomicassets.cpp:453-478` (createschema), `src/atomicassets.cpp:485-509` (extendschema, append-only), `src/atomicassets.cpp:517-563` (setschematyp) Live chain observation (wax.greymass.com `get_table_rows`, `code=atomicassets`, `scope=alien.worlds`, `table=schemas`): the `faces.worlds`-adjacent schema `arms.worlds` returns `format: [{"name":"cardid","type":"uint16"}, {"name":"name","type":"string"}, {"name":"img","type":"image"}, ...]` - an ordered vector matching this layout exactly. @@ -62,7 +62,7 @@ Templates are optional: `mintasset` accepts `template_id = -1` to mint a schemal Changed in V2: mutable template data. The `template_mutables` table (contract table name `templates2`), scoped like `templates` by `collection_name` and keyed by the same `template_id`, holds a `mutable_serialized_data` field that can be set at creation (`createtempl2`) or changed later (`settempldata`). A template row here only exists once non-empty mutable data has been set; `settempldata` with an empty map erases the row instead of leaving an empty one. V1 templates have no mutable data at all - `createtempl` is the only creation action there, and every template's data is fixed forever at creation. -Source: `include/atomicassets.hpp:383-405` (templates and template_mutables tables), `include/atomicassets.hpp:456` (template_counter default), `src/atomicassets.cpp:566-594` (createtempl / createtempl2), `src/atomicassets.cpp:600-624` (deltemplate), `src/atomicassets.cpp:631-653` (locktemplate), `src/atomicassets.cpp:661-689` (redtemplmax), `src/atomicassets.cpp:846-907` (settempldata, emplace/modify/erase branching), `src/atomicassets.cpp:1579-1655` (internal_create_template) +Source: `include/atomicassets.hpp:383-405` (templates and template_mutables tables), `include/atomicassets.hpp:456` (template_counter default), `src/atomicassets.cpp:569-597` (createtempl / createtempl2), `src/atomicassets.cpp:603-627` (deltemplate), `src/atomicassets.cpp:634-656` (locktemplate), `src/atomicassets.cpp:664-692` (redtemplmax), `src/atomicassets.cpp:849-910` (settempldata, emplace/modify/erase branching), `src/atomicassets.cpp:1582-1658` (internal_create_template) Live chain observation (wax.greymass.com, `scope=alien.worlds`, `table=templates`): template `13728` returns `max_supply: 403, issued_supply: 403` (locked at its cap) alongside its `immutable_serialized_data` byte vector; template `17453` shows `max_supply: 0` (unlimited) with `issued_supply: 415`. @@ -74,7 +74,7 @@ An asset's fields: `collection_name` and `schema_name` (fixed at mint time), `te Changed in V2: RAM-payer reassignment. Two actions let an asset's `ram_payer` be reassigned without a transfer, replacing an abandoned custodial-rentals design that never shipped. See [AtomicAssets actions](actions.md#ram-payer-reassignment-replaces-descoped-custodial-rentals) ("RAM-payer reassignment (replaces descoped custodial rentals)"). V1 has neither the reassignment actions nor the abandoned design. -Source: `include/atomicassets.hpp:409-421` (assets table), `include/atomicassets.hpp:455` (asset_counter default), `src/atomicassets.cpp:697-788` (mintasset), `src/atomicassets.cpp:796-836` (setassetdata), `src/atomicassets.cpp:1079-1087` (backasset deprecated) +Source: `include/atomicassets.hpp:409-421` (assets table), `include/atomicassets.hpp:455` (asset_counter default), `src/atomicassets.cpp:700-791` (mintasset), `src/atomicassets.cpp:799-839` (setassetdata), `src/atomicassets.cpp:1082-1090` (backasset deprecated) Live chain observation (wax.api.atomicassets.io `/atomicassets/v1/assets?collection_name=alien.worlds&template_id=13728`): asset `1099511946686`, owned by `wombatmaster`, carries empty `immutable_data` and `mutable_data` objects of its own - all of its displayed attributes come from the template (see [Attribute data precedence](data-precedence.md)). @@ -86,7 +86,7 @@ Three levels of authority operate over a collection and everything scoped under - **Authorized accounts** (`collections.authorized_accounts`, capped at 24) - can create and edit schemas, templates, and assets belonging to the collection. Every action gated this way calls `check_has_collection_auth(account, collection_name)`, which both requires the caller's own authorization and checks list membership; it does not require being the author. - **Notify accounts** (`collections.notify_accounts`, capped at 24, gated by `allow_notify`) - not authorization at all, but a `require_recipient` notification list: every relevant action for the collection will attempt to notify these accounts' smart contracts, so a notify account with a throwing `on_notify` handler can block the action. The 24-account cap on both lists exists partly to bound the low-level partial-row read the contract uses to check membership without deserializing a collection's full (and potentially multi-kilobyte) `serialized_data`. This cap is new in V2 for `notify_accounts`: V1's `addnotifyacc` enforced no limit on the list's size. -Source: `src/atomicassets.cpp:167-442` (author-only and auth-gated actions), `src/atomicassets.cpp:1823-1888` (`partial_read_collection`, `check_has_collection_auth`, `notify_collection_accounts`), `src/atomicassets.cpp:127-128` (24-account cap, createcol), `src/atomicassets.cpp:212` (24-account cap, addcolauth), `src/atomicassets.cpp:274` (24-account cap, addnotifyacc) +Source: `src/atomicassets.cpp:167-445` (author-only and auth-gated actions), `src/atomicassets.cpp:1826-1891` (`partial_read_collection`, `check_has_collection_auth`, `notify_collection_accounts`), `src/atomicassets.cpp:127-128` (24-account cap, createcol), `src/atomicassets.cpp:212` (24-account cap, addcolauth), `src/atomicassets.cpp:274` (24-account cap, addnotifyacc) ## Table scoping summary diff --git a/reference/atomicassets/tables.md b/reference/atomicassets/tables.md index 65dcf5a..3370ce3 100644 --- a/reference/atomicassets/tables.md +++ b/reference/atomicassets/tables.md @@ -1,12 +1,12 @@ --- scope: Complete table reference for the `atomicassets` contract - collections, schemas, templates, assets, offers, balances, config, and the V2-only tables depends-on: [reference/atomicassets/structure.md] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets tables -Complete table reference for the `atomicassets` contract, baselined on tag `v2.0.0-rc4` of `atomicassets-contract` (the release pinned for both `wax-testnet` and `jungle4-testnet`). Struct and typedef citations are to `include/atomicassets.hpp`; behavior citations are to `src/atomicassets.cpp`. "Changed in V2" notes compare against the V1 `atomicassets-contract` source. +Complete table reference for the `atomicassets` contract, baselined on tag `v2.0.0` of `atomicassets-contract` (the release pinned for both `wax-testnet` and `jungle4-testnet`). Struct and typedef citations are to `include/atomicassets.hpp`; behavior citations are to `src/atomicassets.cpp`. "Changed in V2" notes compare against the V1 `atomicassets-contract` source. Live-chain status: see [AtomicAssets V2 upgrade](v2-upgrade.md#deployment-status) ("Deployment status"); the V2-only tables below (`authorswaps`, `schematypes`, `templates2`) do not exist on WAX mainnet yet. An abandoned custodial-rentals design left a `holders` table on unreleased development branches; it ships in no tagged release and is not documented here. See [AtomicAssets actions](actions.md#ram-payer-reassignment-replaces-descoped-custodial-rentals) ("RAM-payer reassignment (replaces descoped custodial rentals)"). @@ -27,11 +27,11 @@ Secondary indexes: none. | `collection_name` | `name` | The collection whose authorship is being reassigned. Also the primary key. | | `current_author` | `name` | The collection's author at the moment the swap was created; re-checked against the live `collections.author` on accept/reject as a consistency guard. | | `new_author` | `name` | The account the swap would make the new author. | -| `acceptance_date` | `uint32_t` | Unix seconds after which `acceptauswap` becomes callable: `now` if the swap was created under the author's `owner` permission, `now + 604800` (one week) otherwise. | +| `acceptance_date` | `uint32_t` | Unix seconds at or after which `acceptauswap` is callable (the boundary second passes): `now` if the swap was created under the author's `owner` permission, `now + 604800` (one week) otherwise. | A row exists only while a swap is pending; `acceptauswap` and `rejectauswap` both erase it. Changed in V2: this table does not exist in V1 (collection authorship there is fixed at creation). -Source: `include/atomicassets.hpp:337-345`, `src/atomicassets.cpp:357-449` (`createauswap`, `acceptauswap`, `rejectauswap`) +Source: `include/atomicassets.hpp:337-345`, `src/atomicassets.cpp:357-445` (`createauswap`, `acceptauswap`, `rejectauswap`) ## collections @@ -55,7 +55,7 @@ Secondary indexes: none. See [AtomicAssets data model structure](structure.md#authorization-and-the-24-account-cap) ("Authorization and the 24-account cap") for why both lists are capped at 24. -Source: `include/atomicassets.hpp:348-359`, `src/atomicassets.cpp:91-166` (`createcol`), `src/atomicassets.cpp:1804-1856` (`partial_read_collection`) +Source: `include/atomicassets.hpp:348-359`, `src/atomicassets.cpp:91-166` (`createcol`), `src/atomicassets.cpp:1807-1859` (`partial_read_collection`) Live chain example (`wax.greymass.com get_table_rows`, `code=atomicassets`, `scope=atomicassets`, `table=collections`, one row, byte fields elided): @@ -81,7 +81,7 @@ Secondary indexes: none. Append-only: `extendschema` is the only action that changes an existing row, and it can only add lines to the end of `format`, never remove or reorder them. -Source: `include/atomicassets.hpp:363-369`, `src/atomicassets.cpp:450-513` (`createschema`, `extendschema`) +Source: `include/atomicassets.hpp:363-369`, `src/atomicassets.cpp:453-516` (`createschema`, `extendschema`) Live chain example (`scope=farmersworld`, `table=schemas`, `lower_bound=memberships`): @@ -111,7 +111,7 @@ Written only by `setschematyp`, which fully replaces the row's `format_type` vec Do not treat the API's `mediatype`/`info` fields as evidence of a `schematypes` row. The atomicassets-api includes `mediatype` and `info` on every attribute of a schema's `format` in its HTTP response even when the on-chain `schematypes` table has no row for that schema: with no descriptor set it defaults `mediatype` to the attribute's own `name` and `info` to `null`. To know whether a real `FORMAT_TYPE` descriptor was set, read the `schematypes` table on chain rather than inferring it from the API's schema response. This synthesis ships in atomicassets-api 2.0.0 (live-confirmed on the wax-testnet deployment, which reports that version on `/health`); deployments on the 1.7 line, including the WAX mainnet reference deployment at the time of the read, return schema `format` entries as plain `{name, type}` with no `mediatype`/`info` fields at all. -Source: `include/atomicassets.hpp:373-379`, `src/atomicassets.cpp:514-565` (`setschematyp`) +Source: `include/atomicassets.hpp:373-379`, `src/atomicassets.cpp:517-568` (`setschematyp`) ## templates @@ -133,7 +133,7 @@ Secondary indexes: none. | `issued_supply` | `uint32_t` | Incremented by every `mintasset` against this template; must stay `< max_supply` when `max_supply > 0`. Also the value `deltemplate` requires to be exactly 0. No action decrements it, `burnasset` included, so it counts lifetime mints rather than circulating supply; a circulating supply must subtract burns. | | `immutable_serialized_data` | `vector` | Set once at `createtempl`/`createtempl2`; no action changes it afterward. | -Source: `include/atomicassets.hpp:383-394`, `src/atomicassets.cpp:566-696` (create/lock/reduce/delete actions), `src/atomicassets.cpp:1613-1689` (`internal_create_template`), `src/atomicassets.cpp:1096-1177` (`burnasset`, which reads the row for the `burnable` check and never writes it) +Source: `include/atomicassets.hpp:383-394`, `src/atomicassets.cpp:569-699` (create/lock/reduce/delete actions), `src/atomicassets.cpp:1582-1658` (`internal_create_template`), `src/atomicassets.cpp:1099-1180` (`burnasset`, which reads the row for the `burnable` check and never writes it) Live chain example (`scope=farmersworld`, `table=templates`, `lower_bound=260638`, byte field elided): @@ -160,7 +160,7 @@ Secondary indexes: none. A row exists only while the template's mutable data is non-empty: `settempldata` erases the row when called with an empty map, and `createtempl2` only creates one when given non-empty `mutable_data`. Its absence means "no mutable template data set for this template," not "empty bytes for it." Changed in V2: this table (and the whole idea of mutable template data) does not exist in V1; `createtempl` there is the only creation action, and every template's data is fixed forever. -Source: `include/atomicassets.hpp:398-405`, `src/atomicassets.cpp:583-599` (`createtempl2`), `src/atomicassets.cpp:846-913` (`settempldata`) +Source: `include/atomicassets.hpp:398-405`, `src/atomicassets.cpp:586-602` (`createtempl2`), `src/atomicassets.cpp:849-916` (`settempldata`) ## assets @@ -183,7 +183,7 @@ Secondary indexes: none. | `immutable_serialized_data` | `vector` | Set once at `mintasset`; never changed by any later action; copied verbatim on every transfer. | | `mutable_serialized_data` | `vector` | Set at `mintasset`; the only one of the two data fields an authorized editor can change later, via `setassetdata`. | -Source: `include/atomicassets.hpp:409-421`, `src/atomicassets.cpp:697-788` (`mintasset`), `src/atomicassets.cpp:796-845` (`setassetdata`), `src/atomicassets.cpp:1096-1177` (`burnasset`), `src/atomicassets.cpp:1665-1761` (`internal_transfer`) +Source: `include/atomicassets.hpp:409-421`, `src/atomicassets.cpp:700-791` (`mintasset`), `src/atomicassets.cpp:799-848` (`setassetdata`), `src/atomicassets.cpp:1099-1180` (`burnasset`), `src/atomicassets.cpp:1668-1764` (`internal_transfer`) Live chain example (`scope=farmersworld`, `table=assets`, one row, byte fields elided): @@ -212,7 +212,7 @@ Secondary indexes: `sender` (`sender.value`, index name `sender`), `recipient` ( | `memo` | `string` | Up to 256 characters. | | `ram_payer` | `name` | Who currently pays for this row's RAM; reassignable to any account via `payofferram` regardless of that account's relationship to the offer. | -Source: `include/atomicassets.hpp:424-442`, `src/atomicassets.cpp:1185-1401` (`createoffer` through `payofferram`) +Source: `include/atomicassets.hpp:424-442`, `src/atomicassets.cpp:1188-1404` (`createoffer` through `payofferram`) Live chain example (`scope=atomicassets`, `table=offers`, one row): @@ -236,7 +236,7 @@ Secondary indexes: none. | `owner` | `name` | The account the balance belongs to. Also the primary key. | | `quantities` | `vector` | One entry per announced token symbol. An entry is added by `announcedepo` (as a zero amount) or incremented by a deposit; an entry is removed entirely once its amount reaches exactly zero via `withdraw`, and the whole row is erased if that was the last entry. A given (owner, symbol) pair that hits zero this way needs `announcedepo` called again before it can receive further deposits, even if the row still exists for other symbols. | -Source: `include/atomicassets.hpp:445-451`, `src/atomicassets.cpp:990-1039` (`announcedepo`), `src/atomicassets.cpp:1040-1078` (`withdraw`), `src/atomicassets.cpp:1402-1444` (`receive_token_transfer`), `src/atomicassets.cpp:1768-1801` (`internal_decrease_balance`) +Source: `include/atomicassets.hpp:445-451`, `src/atomicassets.cpp:993-1042` (`announcedepo`), `src/atomicassets.cpp:1043-1081` (`withdraw`), `src/atomicassets.cpp:1405-1447` (`receive_token_transfer`), `src/atomicassets.cpp:1771-1804` (`internal_decrease_balance`) Live chain example (`scope=atomicassets`, `table=balances`, three rows): diff --git a/reference/atomicassets/v2-upgrade.md b/reference/atomicassets/v2-upgrade.md index 608f424..31e9fb9 100644 --- a/reference/atomicassets/v2-upgrade.md +++ b/reference/atomicassets/v2-upgrade.md @@ -1,7 +1,7 @@ --- scope: What changed in the AtomicAssets V2 upgrade, why it is additive and in place, the indexer and chain compatibility surface it creates, and where it is live depends-on: [] -key-modules: ["atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp, include/atomicassets.hpp"] +key-modules: ["atomicassets-contract (v2.0.0): src/atomicassets.cpp, include/atomicassets.hpp"] --- # AtomicAssets V2 upgrade @@ -20,6 +20,10 @@ Re-check `tokenconfigs.version` (or `get_abi`) on any target chain before relyin Source: live chain read, `POST https://wax.greymass.com/v1/chain/get_abi {"account_name":"atomicassets"}`, checked 2026-07-06 +The testnet deployments are the GA release byte for byte: `get_code_hash` for `atomicassets` returns `962a93e1adde9779d3afb84983cee076c3d2b50b0473c99fb0fe02573a7b7242` on both wax-testnet and jungle4, equal to the `atomicassets.wasm` line of the `v2.0.0` Release's `SHA256SUMS`, so the tag this corpus pins and the code the testnets execute are identical. + +Source: live chain reads, `POST /v1/chain/get_code_hash {"account_name":"atomicassets"}` on `waxtestnet.greymass.com` and `jungle4.api.eosnation.io`; the `SHA256SUMS` asset of the `atomicassets-contract` `v2.0.0` Release + AtomicMarket follows the same additive pattern, but its V2 royalty tables are live on testnet. A `get_table_rows` read of the `royaltyconf` table (`code=atomicmarket`, `scope=atomicmarket`) succeeds on wax-testnet, where it is populated (`royaltycol11` among others carries a config), and on jungle4, where the table exists but is unseeded; on WAX mainnet the same read fails with `contract_table_query_exception` (code 3060003) because the V2 `setcode` has not been applied there. The full V2 royalty split is therefore live-chain-verified, not merely source-verified: a real wax-testnet sale settles founders, template, and attribute payouts that sum exactly to the collection fee (see [AtomicMarket fees and royalties](../atomicmarket/fees-and-royalties.md)). `config.version` is not a reliable V2 signal. It reads `"1.3.3"` on all three chains, including the V2 testnet and jungle4 deployments, because no `setversion` has run since the V2 `setcode`. Use table presence as the authoritative check instead: a `royaltyconf` read that returns rows (even zero) means the V2 code is deployed, while one that errors with `contract_table_query_exception` means V1, exactly as `get_abi`'s action/table list is the authoritative check for `atomicassets` above. diff --git a/reference/atomicmarket/actions.md b/reference/atomicmarket/actions.md index 1a8fd83..e5384ca 100644 --- a/reference/atomicmarket/actions.md +++ b/reference/atomicmarket/actions.md @@ -1,7 +1,7 @@ --- scope: Action reference for the `atomicmarket` contract - admin, marketplaces, balances, royalty config, sales, auctions, buyoffers, template buyoffers, and RAM depends-on: [reference/atomicmarket/tables.md, reference/atomicassets/actions.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp, include/atomicmarket.hpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp, include/atomicmarket.hpp"] --- # AtomicMarket actions diff --git a/reference/atomicmarket/fees-and-royalties.md b/reference/atomicmarket/fees-and-royalties.md index 0c7b74a..7b7b86d 100644 --- a/reference/atomicmarket/fees-and-royalties.md +++ b/reference/atomicmarket/fees-and-royalties.md @@ -1,7 +1,7 @@ --- scope: The full fee model for a sale, auction, or buyoffer settlement on `atomicmarket` - marketplace fees, fee bounds, collection fee timing, and royalty splits depends-on: [reference/atomicmarket/tables.md, reference/atomicmarket/marketplaces.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp, include/atomicmarket.hpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp, include/atomicmarket.hpp"] --- # AtomicMarket fees and royalties diff --git a/reference/atomicmarket/marketplaces.md b/reference/atomicmarket/marketplaces.md index cab9263..892e141 100644 --- a/reference/atomicmarket/marketplaces.md +++ b/reference/atomicmarket/marketplaces.md @@ -1,7 +1,7 @@ --- scope: How a frontend or dapp registers as a marketplace on the shared `atomicmarket` contract, and how maker/taker attribution and fee crediting flow through it depends-on: [reference/atomicmarket/tables.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp, include/atomicmarket.hpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp, include/atomicmarket.hpp"] --- # AtomicMarket marketplaces diff --git a/reference/atomicmarket/ram.md b/reference/atomicmarket/ram.md index 40f04ce..b2e3a15 100644 --- a/reference/atomicmarket/ram.md +++ b/reference/atomicmarket/ram.md @@ -1,7 +1,7 @@ --- scope: Who pays RAM for each `atomicmarket` table row, the voluntary pay*ram re-homing actions, and sizing implications for a high-volume marketplace or dapp depends-on: [reference/atomicmarket/tables.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp, include/atomicmarket.hpp", "AntelopeIO/leap (v5.0.3): chain RAM-billing constants"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp, include/atomicmarket.hpp", "AntelopeIO/leap (v5.0.3): chain RAM-billing constants"] --- # AtomicMarket RAM diff --git a/reference/atomicmarket/tables.md b/reference/atomicmarket/tables.md index 20d5760..1656fe1 100644 --- a/reference/atomicmarket/tables.md +++ b/reference/atomicmarket/tables.md @@ -1,7 +1,7 @@ --- scope: Table reference for the `atomicmarket` contract - sales, auctions, buyoffers, template buyoffers, marketplaces, balances, config, and the royalty tables depends-on: [reference/atomicmarket/fees-and-royalties.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp, include/atomicmarket.hpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp, include/atomicmarket.hpp"] --- # AtomicMarket tables diff --git a/reference/atomicmarket/v2-changes.md b/reference/atomicmarket/v2-changes.md index 36ab665..f648af7 100644 --- a/reference/atomicmarket/v2-changes.md +++ b/reference/atomicmarket/v2-changes.md @@ -1,7 +1,7 @@ --- scope: V2 changes index for the `atomicmarket` contract, plus the two facts that live only here - the defensive guards and uint64 JSON serialization as strings depends-on: [reference/atomicmarket/fees-and-royalties.md, reference/atomicmarket/actions.md, reference/atomicmarket/tables.md] -key-modules: ["atomicmarket-contract (v2.0.0-rc2): src/atomicmarket.cpp, include/atomicmarket.hpp"] +key-modules: ["atomicmarket-contract (v2.0.0): src/atomicmarket.cpp, include/atomicmarket.hpp"] --- # AtomicMarket V2 changes diff --git a/reference/media.md b/reference/media.md index bc1adc3..54246e6 100644 --- a/reference/media.md +++ b/reference/media.md @@ -4,7 +4,7 @@ depends-on: - reference/atomicassets/serialization.md - reference/atomicassets/custom-types.md - reference/atomicassets/data-precedence.md -key-modules: ["atomicassets-contract (v2.0.0-rc4): include/atomicdata.hpp (image/ipfs wire types); live reads of wax.api.atomicassets.io and public IPFS gateways"] +key-modules: ["atomicassets-contract (v2.0.0): include/atomicdata.hpp (image/ipfs wire types); live reads of wax.api.atomicassets.io and public IPFS gateways"] --- # Media conventions diff --git a/reference/validation.md b/reference/validation.md index 28f25ef..b39189a 100644 --- a/reference/validation.md +++ b/reference/validation.md @@ -10,8 +10,8 @@ This log traces how every fact in `reference/` and `guides/` was checked before ## Pinned baselines -- `atomicassets-contract` at `v2.0.0-rc4` -- `atomicmarket-contract` at `v2.0.0-rc2` +- `atomicassets-contract` at `v2.0.0` +- `atomicmarket-contract` at `v2.0.0` - `atomicassets-api` at its current `main` branch state (no release tag; indexer behavior and API surface are read from the running source tree; streaming and rate-limit pages pin `f6419858`) - `atomictools-contract` at commit `d89ce79e4` (the upstream repository has no release tag; the deployed `atomictoolsx` ABI on WAX matches this commit exactly) - `atomicassets-sdk` at tag `v2.1.1`, commit `5c70c62` (published as `@atomichub/atomicassets` 2.1.1) @@ -25,7 +25,7 @@ A page's `key-modules` frontmatter names the specific baseline(s) it draws from; ## Caveat: V2 is live on WAX testnet, not on WAX mainnet -WAX mainnet still runs the V1 `atomicassets` and `atomicmarket` contracts (confirmed by live `get_abi` and `get_table_rows` reads; see `reference/atomicassets/v2-upgrade.md`). WAX testnet runs the full V2 contracts: the V2 tables are present and populated, and jungle4 carries the V2 code with unseeded tables. Many V2 contract-behavior facts in this repository are therefore still tiered `source-read` because they were written from the rc4/rc2 source, but the create, trade, and read integrator flows have been executed end-to-end against live V2 on wax-testnet (the cold-validation harness, `packages/testnet-e2e/cold-validation.md`): a full asset lifecycle, a sale settling founders/template/attribute royalties that sum exactly to the collection fee, and a full read reconstruction over both the API and chain tables. Facts confirmed by those runs are tiered `live-chain`/`both` and noted per page below. A `source-read` tier means only that chain execution has not confirmed that specific fact, not lesser confidence in the reading. Hosted-API facts (pagination, lifecycle states) and chain-RPC facts (error codes, serialization) are checked against the live deployment and nodeos; V1 and V2 share the indexer and RPC layer for everything those facts describe. +WAX mainnet still runs the V1 `atomicassets` and `atomicmarket` contracts (confirmed by live `get_abi` and `get_table_rows` reads; see `reference/atomicassets/v2-upgrade.md`). WAX testnet runs the full V2 contracts: the V2 tables are present and populated, and jungle4 carries the V2 code with unseeded tables. Many V2 contract-behavior facts in this repository are therefore still tiered `source-read` because they were written from the pinned `v2.0.0` source, but the create, trade, and read integrator flows have been executed end-to-end against live V2 on wax-testnet (the cold-validation harness, `packages/testnet-e2e/cold-validation.md`): a full asset lifecycle, a sale settling founders/template/attribute royalties that sum exactly to the collection fee, and a full read reconstruction over both the API and chain tables. Facts confirmed by those runs are tiered `live-chain`/`both` and noted per page below. A `source-read` tier means only that chain execution has not confirmed that specific fact, not lesser confidence in the reading. Hosted-API facts (pagination, lifecycle states) and chain-RPC facts (error codes, serialization) are checked against the live deployment and nodeos; V1 and V2 share the indexer and RPC layer for everything those facts describe. ## Pages @@ -39,33 +39,33 @@ WAX mainnet still runs the V1 `atomicassets` and `atomicmarket` contracts (confi | `reference/sdk/atomicassets.md` | `atomicassets-sdk` (`v2.1.1`, `5c70c62`): `src/index.ts`, `src/API/Explorer/index.ts`, `src/API/Rpc/index.ts`, `src/Actions/Generator.ts`, `src/Serialization/index.ts`, `src/Schema/index.ts`, `src/Networks.ts`, `package.json`, `test/explorer-url.test.ts`; live reads of `wax.api.atomicassets.io` | both | The getter-and-route table, the serialization split, action shapes, and error types are read from the 2.1.1 source, each section citing file and line. Source-read at 2.1.1: the lazy `action` getter (construction starts no request), percent-encoding of path segments and of both sides of every query pair, the empty-and-dot-segment guard added in 2.1.1 (its two throw messages, the sixteen guarded getters, the plain `Error` rather than an `ApiError`, and that nothing is sent, all read from `encodeSegment` and the paired test), the numeric ABI-type guards and the fields they cover, the `backasset` and `tokens_to_back` deprecation, and the one-object-versus-array asymmetry against the market builder. The `getTemplateStats` row now reads `(collection, id)`, correcting a `name` the 2.1.1 signature renamed. ExplorerApi reads, a serialization round-trip against a live schema format, the 8-arg `mintasset` output, and the network factories were executed against the built SDK at the earlier 2.0.0 pin and the affected signatures re-read at 2.1.1. The zero-runtime-deps and `sideEffects` facts are from `package.json`. | | `reference/sdk/atomicmarket.md` | `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/index.ts`, `src/API/Explorer/index.ts`, `src/API/Explorer/Objects.ts`, `src/API/Explorer/Enums.ts`, `src/API/Explorer/Params.ts`, `src/Actions/Generator.ts`, `src/Actions/Delphi.ts`, `src/Actions/Symbols.ts`, `src/Tables.ts`, `src/Networks.ts`, `package.json`, `test/path-segments.test.ts`; live reads of `wax.api.atomicassets.io` and `test.wax.api.atomicassets.io` | both | The read-surface table, the 31-method action surface (26 actions plus five composers), the composer contracts, and the delphi settlement math are read from the 2.4.1 source, each section citing file and line. Source-read at 2.4.1: the empty-and-dot-segment guard (its two throw messages, the thirteen guarded readers, the plain `Error` that travels out of `getRoyaltyConfig` because only a 416 `ApiError` maps to `null`), and the payout filter surfaces `RoyaltyPayoutApiParams` and `RoyaltyAccountApiParams`. Live-chain: `/atomicmarket/v2/sales` and its `_count` answer 200 on WAX mainnet; the mainnet royalty route answers HTTP 416 with `Royalty config not found`, which corrects the 404 this page previously claimed and inverts the guard advice, since `getRoyaltyConfig` maps 416 to `null`; the WAX testnet royalty reads and the testnet `getConfig` sample (contract `version: 2.0.0`, the `waxpusd` pair) were read live, and mainnet `getConfig` reads `1.3.3`. Live-chain for the 2.4.0 payout ledger: the testnet `/royalties/payouts`, `/payouts/_count`, and `/accounts/{account}` routes answer 200 with rows matching `IRoyaltyPayout` and `IRoyaltyAccountTotal` field for field, the `_count` value arrives as the string `"20"`, the sampled rows confirm the category-to-linkage rule, and the same three routes on WAX mainnet answer 200 with an empty list and a zero count, which is the V1-chain case. The added `market_contract`, `collection_name`, timestamp, and `lookup_hash` fields on the config and rule rows are live-read from the testnet royalty routes as well as declared in `Objects.ts`. The worked `deriveSettlementAmount` figures are computed from the pinned formula against that live pair, not observed on chain. | | `reference/atomicassets-api.md` | `atomicassets-api`: `package.json`, `src/api/server.ts` | source-read | Cites repo metadata and the documentation-server source; no live probe cited. | -| `reference/atomicassets/actions.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp`; `AntelopeIO/leap` (v5.0.3) billing constants; live WAX mainnet `get_transaction` read | both | Every action cites specific header and implementation line ranges. The 112-byte new-scope transfer charge is checked both ways: computed from the pinned leap billing constants and observed as the sender's `account_ram_deltas` entry in a live WAX mainnet transfer. | -| `reference/atomicassets/backing-tokens.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | Cites `announcedepo`, `withdraw`, `addconftoken`, `burnasset`, and the V2 `backasset` abort by line range. | -| `reference/atomicassets/custom-types.md` | `atomicassets-contract` (v2.0.0-rc4): `include/atomicdata.hpp`, `include/checkformat.hpp`, `src/atomicassets.cpp` | source-read | Includes one negative check (`setschematyp` confirmed absent from the V1 source tree) alongside the V2 citations. | -| `reference/atomicassets/data-precedence.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicdata.hpp` | source-read | One fact is cross-checked against `atomicassets-api src/api/namespaces/atomicassets/format.ts` in addition to contract source. | -| `reference/atomicassets/notifications.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | One entry also cites the V1 contract tree (`contracts/atomicassets-contract`) for a V1-vs-V2 comparison. | -| `reference/atomicassets/serialization.md` | `atomicassets-contract` (v2.0.0-rc4): `include/atomicdata.hpp`, `include/checkformat.hpp` | source-read | One entry confirms identical serialize/deserialize logic between the V1 and V2 source trees. | -| `reference/atomicassets/structure.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | Foundational data-model page; every section cites header and implementation ranges. | -| `reference/atomicassets/tables.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | One table per section, each with its own `Source:` line. | -| `reference/atomicassets/v2-upgrade.md` | `atomicassets-contract` (v2.0.0-rc4) source; live `get_abi`/`get_table_rows` reads against WAX mainnet, jungle4, and wax-testnet | both | The additive-upgrade mechanics are source-read; the deployment-status section is live-chain, cross-checked across all three chains (mainnet V1, jungle4 and wax-testnet V2). Records that `config.version` reads `1.3.3` even on the V2 deployments, so table presence, not the version string, is the authoritative V2 check. | -| `reference/atomicmarket/actions.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`, `include/atomicmarket.hpp` | source-read | Every action cites header and implementation line ranges. | -| `reference/atomicmarket/fees-and-royalties.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`, `include/atomicmarket.hpp`; live wax-testnet sale settlement | both | Cites `internal_payout_sale`, fee-bound actions, and the royalty split/log actions by line range. The four-layer fee stack, the founders/template/attribute split summing exactly to the collection fee, the standing 2% WAX bonus fee, and the `/sales/{id}/logs` payout read are live-chain-confirmed by a cold-validation trade run on wax-testnet. The no-fee-parameter `assertsale` note (no per-listing seller cap on the execution-time fee) is source-read. | -| `reference/atomicmarket/marketplaces.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`, `include/atomicmarket.hpp` | source-read | Cites `regmarket`, `is_valid_marketplace`, and the maker/taker crediting logic inside `internal_payout_sale`. | -| `reference/atomicmarket/ram.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`, `include/atomicmarket.hpp`; `AntelopeIO/leap` (v5.0.3) billing constants; live WAX mainnet `get_transaction` reads | both | Cites the internal balance helpers and each `pay*ram` action by line range. The 121 + 16N balances-row byte cost, which holds for any symbol count up to 127, is checked both ways: computed from the pinned leap billing constants plus the packed row shape, and observed at exactly 137 bytes (N=1) in three live WAX mainnet deposit-and-settlement transactions. | -| `reference/atomicmarket/tables.md` | `atomicmarket-contract` (v2.0.0-rc2): `include/atomicmarket.hpp` | source-read | One table per section, each with its own header line-range citation. | -| `reference/atomicmarket/v2-changes.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp` | source-read | The defensive-guards section has an explicit `Source:` line. The "large integers serialize as strings" section describes live nodeos JSON-serialization behavior and carries no dedicated citation in this page; it is consistent with, and narrower than, the live-chain uint64 facts in `guides/querying-the-api.md`. | +| `reference/atomicassets/actions.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp`; `AntelopeIO/leap` (v5.0.3) billing constants; live WAX mainnet `get_transaction` read | both | Every action cites specific header and implementation line ranges. The 112-byte new-scope transfer charge is checked both ways: computed from the pinned leap billing constants and observed as the sender's `account_ram_deltas` entry in a live WAX mainnet transfer. | +| `reference/atomicassets/backing-tokens.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | Cites `announcedepo`, `withdraw`, `addconftoken`, `burnasset`, and the V2 `backasset` abort by line range. | +| `reference/atomicassets/custom-types.md` | `atomicassets-contract` (v2.0.0): `include/atomicdata.hpp`, `include/checkformat.hpp`, `src/atomicassets.cpp` | source-read | Includes one negative check (`setschematyp` confirmed absent from the V1 source tree) alongside the V2 citations. | +| `reference/atomicassets/data-precedence.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicdata.hpp` | source-read | One fact is cross-checked against `atomicassets-api src/api/namespaces/atomicassets/format.ts` in addition to contract source. | +| `reference/atomicassets/notifications.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | One entry also cites the V1 contract tree (`contracts/atomicassets-contract`) for a V1-vs-V2 comparison. | +| `reference/atomicassets/serialization.md` | `atomicassets-contract` (v2.0.0): `include/atomicdata.hpp`, `include/checkformat.hpp` | source-read | One entry confirms identical serialize/deserialize logic between the V1 and V2 source trees. | +| `reference/atomicassets/structure.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | Foundational data-model page; every section cites header and implementation ranges. | +| `reference/atomicassets/tables.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | One table per section, each with its own `Source:` line. | +| `reference/atomicassets/v2-upgrade.md` | `atomicassets-contract` (v2.0.0) source; live `get_abi`/`get_table_rows` reads against WAX mainnet, jungle4, and wax-testnet | both | The additive-upgrade mechanics are source-read; the deployment-status section is live-chain, cross-checked across all three chains (mainnet V1, jungle4 and wax-testnet V2). Records that `config.version` reads `1.3.3` even on the V2 deployments, so table presence, not the version string, is the authoritative V2 check. | +| `reference/atomicmarket/actions.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`, `include/atomicmarket.hpp` | source-read | Every action cites header and implementation line ranges. | +| `reference/atomicmarket/fees-and-royalties.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`, `include/atomicmarket.hpp`; live wax-testnet sale settlement | both | Cites `internal_payout_sale`, fee-bound actions, and the royalty split/log actions by line range. The four-layer fee stack, the founders/template/attribute split summing exactly to the collection fee, the standing 2% WAX bonus fee, and the `/sales/{id}/logs` payout read are live-chain-confirmed by a cold-validation trade run on wax-testnet. The no-fee-parameter `assertsale` note (no per-listing seller cap on the execution-time fee) is source-read. | +| `reference/atomicmarket/marketplaces.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`, `include/atomicmarket.hpp` | source-read | Cites `regmarket`, `is_valid_marketplace`, and the maker/taker crediting logic inside `internal_payout_sale`. | +| `reference/atomicmarket/ram.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`, `include/atomicmarket.hpp`; `AntelopeIO/leap` (v5.0.3) billing constants; live WAX mainnet `get_transaction` reads | both | Cites the internal balance helpers and each `pay*ram` action by line range. The 121 + 16N balances-row byte cost, which holds for any symbol count up to 127, is checked both ways: computed from the pinned leap billing constants plus the packed row shape, and observed at exactly 137 bytes (N=1) in three live WAX mainnet deposit-and-settlement transactions. | +| `reference/atomicmarket/tables.md` | `atomicmarket-contract` (v2.0.0): `include/atomicmarket.hpp` | source-read | One table per section, each with its own header line-range citation. | +| `reference/atomicmarket/v2-changes.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp` | source-read | The defensive-guards section has an explicit `Source:` line. The "large integers serialize as strings" section describes live nodeos JSON-serialization behavior and carries no dedicated citation in this page; it is consistent with, and narrower than, the live-chain uint64 facts in `guides/querying-the-api.md`. | | `reference/chain.md` | Live `nodeos`/WAX RPC behavior (`/v1/chain/get_account`); nodeos `chain_plugin.cpp` referenced for the error-message format | live-chain | No dedicated `Source:` line in this page. The error code and HTTP behavior are a live-RPC fact; the page also names the nodeos source file that emits the message text, which is not independently re-verified here. | | `reference/contract-releases.md` | `atomicassets-contract` / `atomicmarket-contract`: `Makefile`, `scripts/patch-abi.py`, CI release workflow | source-read | No dedicated `Source:` line and no version pin in this page's frontmatter (build tooling applies across releases, not to one tag). Resource-usage figures (NET/CPU for `setcode`) read as measured observations rather than a cited source or a live probe; treat those magnitudes as approximate. | | `reference/wharfkit.md` | `@wharfkit/antelope` client library source, pinned to `1.1.1` | source-read | No dedicated `Source:` line; each fact names the library behavior and, for one, an `@attention` note in the library's own source. Re-check on any `@wharfkit/antelope` upgrade, as the page itself states. | -| `guides/asset-lifecycle.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp`; `atomicassets-sdk` (`v2.1.1`, `5c70c62`): `src/Actions/Generator.ts` | source-read | Creator-flow walkthrough; every step cites the underlying action's source range. The SDK mint example and the numeric-guard note are source-read from the 2.1.1 builder, not executed: the guarded fields, the `-1` sentinel, and the single-object return shape are read from `Generator.ts` by line. | -| `guides/auctions.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`; `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/Actions/Generator.ts`; live `get_table_rows` curl example against `wax.greymass.com` | both | Lifecycle steps cite contract source; one section shows a live `get_table_rows` curl call to illustrate reading auction state. The composer section is source-read from the 2.4.1 builder: the announce-then-transfer order, the `auction` memo literal, and the `duration` uint32 check are read by line. | -| `guides/buyoffers.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`; `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/Actions/Generator.ts` | source-read | Every action (create, accept, decline, cancel, template variants) cites its source range. The two composer sections are source-read from the 2.4.1 builder: that `acceptbuyo` and `fulfilltbuyo` have no standalone builder method, the emitted order and memo literals, and the `allow_v1_bundle_buyoffer` throw are read by line. | -| `guides/deposits.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`, `include/atomicmarket.hpp` | source-read | Balance ledger mechanics cite `internal_add_balance`, `internal_decrease_balance`, and `withdraw` by range. | +| `guides/asset-lifecycle.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp`; `atomicassets-sdk` (`v2.1.1`, `5c70c62`): `src/Actions/Generator.ts` | source-read | Creator-flow walkthrough; every step cites the underlying action's source range. The SDK mint example and the numeric-guard note are source-read from the 2.1.1 builder, not executed: the guarded fields, the `-1` sentinel, and the single-object return shape are read from `Generator.ts` by line. | +| `guides/auctions.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`; `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/Actions/Generator.ts`; live `get_table_rows` curl example against `wax.greymass.com` | both | Lifecycle steps cite contract source; one section shows a live `get_table_rows` curl call to illustrate reading auction state. The composer section is source-read from the 2.4.1 builder: the announce-then-transfer order, the `auction` memo literal, and the `duration` uint32 check are read by line. | +| `guides/buyoffers.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`; `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/Actions/Generator.ts` | source-read | Every action (create, accept, decline, cancel, template variants) cites its source range. The two composer sections are source-read from the 2.4.1 builder: that `acceptbuyo` and `fulfilltbuyo` have no standalone builder method, the emitted order and memo literals, and the `allow_v1_bundle_buyoffer` throw are read by line. | +| `guides/deposits.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`, `include/atomicmarket.hpp` | source-read | Balance ledger mechanics cite `internal_add_balance`, `internal_decrease_balance`, and `withdraw` by range. | | `guides/links.md` | `atomictools-contract` (commit `d89ce79e4`): `src/link.cpp`; `atomicassets-api` `src/filler/handlers/atomictools`; live `get_table_rows` and `wax.api.atomicassets.io/atomictools/v1` probes | both | Lifecycle steps cite contract source; the funding-by-transfer, signature claim, and cancel flows are source-read. The chain-read curl examples and the hosted-API state table (LinkState 0-3) are live-confirmed, the enum cross-checked against the indexer handler. No transactions were broadcast. | -| `guides/notification-integration.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | Handler wiring, exact ABI signatures, and the notification emission sites are cited by line range against the pinned contract. Two claims about the Antelope runtime (what authorization a notification handler sees, and which payer a notification context may bill for RAM) are not properties of the pinned source; the page states them as safe practice, anchored to the contract's own `receive_token_transfer` (`get_first_receiver` authentication, `same_payer` writes) rather than asserting a runtime rule. | -| `guides/offers.md` | `atomicassets-contract` (v2.0.0-rc4): `src/atomicassets.cpp` | source-read | The underlying `createoffer`/`acceptoffer` primitive and how AtomicMarket sales build on it, all cited to contract source. | +| `guides/notification-integration.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp`, `include/atomicassets.hpp` | source-read | Handler wiring, exact ABI signatures, and the notification emission sites are cited by line range against the pinned contract. Two claims about the Antelope runtime (what authorization a notification handler sees, and which payer a notification context may bill for RAM) are not properties of the pinned source; the page states them as safe practice, anchored to the contract's own `receive_token_transfer` (`get_first_receiver` authentication, `same_payer` writes) rather than asserting a runtime rule. | +| `guides/offers.md` | `atomicassets-contract` (v2.0.0): `src/atomicassets.cpp` | source-read | The underlying `createoffer`/`acceptoffer` primitive and how AtomicMarket sales build on it, all cited to contract source. | | `guides/querying-the-api.md` | Synthesizes `reference/api.md`, `reference/wharfkit.md`, `reference/chain.md`, `reference/atomicmarket/v2-changes.md`, `reference/sdk/atomicassets.md`; live curl examples against `wax.api.atomicassets.io` | both | This page has no `Source:` line of its own; it links back to the reference page carrying each cited fact and shows live curl output for the pagination and lifecycle-state examples. The percent-encoding section is source-read from both SDK Explorer clients and live-confirmed for the colon case: `data:text.rarity=Common` and `data%3Atext.rarity=Common` return the same rows from the WAX deployment. The testnet-host guidance is promoted to its own section with a host table and no new facts. | -| `guides/sales.md` | `atomicmarket-contract` (v2.0.0-rc2): `src/atomicmarket.cpp`; `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/Actions/Generator.ts`, `src/Actions/Delphi.ts`; live `get_table_rows` curl examples against `wax.greymass.com` | both | Lifecycle steps (`announcesale`, `purchasesale`, `cancelsale`, Delphi pricing) cite contract source; three sections show live `get_table_rows` curl calls. The two composer sections and the `settlement_quantity` rules are source-read from the 2.4.1 builder: the emitted action order, the `sale` and `deposit` memo literals, the `allow_v1_bundle_sale` throw, and both settlement branches are read by line. No transaction was broadcast. | +| `guides/sales.md` | `atomicmarket-contract` (v2.0.0): `src/atomicmarket.cpp`; `atomicmarket-sdk` (`v2.4.1`, `437300b`): `src/Actions/Generator.ts`, `src/Actions/Delphi.ts`; live `get_table_rows` curl examples against `wax.greymass.com` | both | Lifecycle steps (`announcesale`, `purchasesale`, `cancelsale`, Delphi pricing) cite contract source; three sections show live `get_table_rows` curl calls. The two composer sections and the `settlement_quantity` rules are source-read from the 2.4.1 builder: the emitted action order, the `sale` and `deposit` memo literals, the `allow_v1_bundle_sale` throw, and both settlement branches are read by line. No transaction was broadcast. | | `guides/signing.md` | `@wharfkit/session` (1.6.1): `src/index.ts`, `src/session.ts`, `src/transact.ts`; `@wharfkit/common` (1.5.0): `src/common/chains.ts`; `@wharfkit/wallet-plugin-privatekey` (1.1.0): `src/index.ts`; live `GET /v1/chain/get_info` against one public node per chain in the table | both | Live-chain: every chain id on the page was read from a running node (`wax.greymass.com`, `waxtestnet.greymass.com`, `jungle4.api.eosnation.io`, `vaulta.api.atomicassets.io`, `xpr.api.atomicassets.io`, `test.xpr.api.atomicassets.io`), and the six values match the constants in the pinned `@wharfkit/common` source, so the table is confirmed twice over. The no-credential read claim is live-chain too: an anonymous `GET /atomicassets/v1/assets?limit=1` against the hosted WAX deployment and an anonymous `get_table_rows` of `atomicassets` `collections` both answer with rows. Source-read at the pinned versions: the `Session` constructor's required fields, its two identity branches and the exact throw text, `actor` and `permission` reading off `permissionLevel`, the `TransactArgs` shapes, the re-export set that makes two packages enough, and the private-key plugin's single-argument constructor and digest signing. No transaction was signed or broadcast. The V2 deployment sentence carries no source of its own and cites `reference/atomicassets/v2-upgrade.md`. | | `guides/testing-with-vert.md` | `@atomichub/vert` (2.2.0, commit `a8a4160`): `src/antelope/blockchain.ts`, `src/antelope/vm.ts`, `src/antelope/table.ts`, `examples/` | source-read | Cites the emulator, VM host functions, and table store by line range. Beyond the source read, every code snippet was executed: the library's own suite runs 35 passing on Node 22, the `fixtures` and `timer` examples pass end-to-end, and purpose-built probe contracts confirmed the notification/inline transaction-context limit, the `set`-injected `modify` abort, the permission-exists throw, and the `createContract` load timing. Tiered source-read rather than live-chain because in-process WASM emulation is not a chain read. | diff --git a/tutorials/first-collection.md b/tutorials/first-collection.md index 77a6445..12d1b78 100644 --- a/tutorials/first-collection.md +++ b/tutorials/first-collection.md @@ -3,7 +3,7 @@ scope: The one path from an empty WAX testnet account to a minted asset, through depends-on: [guides/signing.md, guides/asset-lifecycle.md, reference/atomicassets/structure.md, reference/sdk/atomicassets.md] key-modules: - "atomicassets-sdk (v2.1.1, 5c70c62): src/Actions/Generator.ts" - - "atomicassets-contract (v2.0.0-rc4): src/atomicassets.cpp" + - "atomicassets-contract (v2.0.0): src/atomicassets.cpp" --- # Mint your first asset on testnet