Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/contracts-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

# scripts/release-notes.sh needs only bash, git, awk and sed, and its
# paired test builds its own throwaway repository, so it sits outside the
# harness guard below and runs before the CDT install. Every ref that
# carries this step also carries the script, so the step is unconditional.
- name: Run release-notes composer test
run: bash scripts/release-notes.test.sh

- name: Check for test harness
id: harness
run: |
Expand Down
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Changelog

Notable changes to the AtomicAssets contract. This file starts at 2.0.0; the
releases published before it live in
[GitHub Releases](https://github.com/atomicassets/atomicassets-contract/releases).

Entry headings keep the `## [X.Y.Z] - YYYY-MM-DD` form. Each entry opens with a
summary line, then carries the sections that `RELEASING.md` defines, in that
order; the entry is the editorial text of the version's GitHub Release. This
project follows semantic versioning.

## [2.0.0] - 2026-08-03

The AtomicAssets v2 standard contract: mutable templates, per-field schema media types, collection author succession, template maintenance actions and a contract-wide CPU reduction.

### Breaking changes

- `backasset` fails unconditionally with `Native backing has been deprecated on the AtomicAssets Contract`, and `mintasset` rejects a non-empty `tokens_to_back`. Both actions stay in the ABI, so an ABI diff does not show the change and an integration that backs assets starts failing at the upgrade. Value already backed is not stranded: burning an asset still releases its `backed_tokens` to the owner's balance, and `withdraw`, `announcedepo` and the deposit path are unchanged. `0907db9`
- `createtempl` and `createtempl2` reject a template whose assets would be neither transferable nor burnable, with `A template cannot be both non-transferable and non-burnable`. Such an asset could never move and could never be destroyed, so it would hold its owner's RAM permanently. Every other flag combination stays valid, and the check runs at creation, so templates already in that state keep working. `0907db9`
- `addcolauth` and `addnotifyacc` refuse to extend a list that already holds 24 accounts, where v1 enforced no limit. These lists are walked on every notifying action. A collection already above the cap keeps every entry it has and can still remove them. `89774e9`
- `createcol` rejects more than 24 accounts in either list, the cap the incremental actions enforce. Without it, one transaction seeds a collection past the read budget. (#23)
- `atomicassets-interface.hpp` reaches its tables through accessor methods, `get_collections()`, `get_offers()`, `get_assets(owner)` and the rest, rather than the member instances v1 declared. A consumer contract that vendors the header changes its call sites. `0036796`

### Upgrading

| Asset | sha256 |
| --- | --- |
| `atomicassets.wasm` | `962a93e1adde9779d3afb84983cee076c3d2b50b0473c99fb0fe02573a7b7242` |
| `atomicassets.abi` | `b6389fdde10a16f2d94b12bb10a67b676f6449b1293b57cc0b18256652cfef68` |

- The wasm sha256 equals the on-chain code hash, so `get_code_hash` confirms which bytes are running. The attached `SHA256SUMS` carries the same two values.
- The ABI is additive against v1: nothing is removed and no existing struct changes shape. The published ABI is the legacy-compat build, where `vector<uint8_t>` fields render as `uint8[]` and the attribute-map pair fields keep their v1 `key` and `value` spellings (CDT 4.1 emits `first` and `second`, and the release build patches them back), so a v1 client or indexer keeps working unchanged. The ABI version moves from `eosio::abi/1.1` to `1.2`, and the behavior changes above are not expressed in the ABI at all.
- The final surface is 47 actions and 11 tables. Existing tables (`assets`, `templates`, `schemas`, `collections`, `config`, `offers`, `balances`, `tokenconfigs`) keep their layout, and the added tables are `templates2`, `schematypes` and `authorswaps`.
- The deploy is a `setcode` plus `setabi`. On-chain state is preserved and no migration action runs.
- A chain that ran the rc1 to rc3 candidates clears the `holders` table before this deploy. No action in this release can erase such a row, and the RAM it occupies is stranded. A chain coming from v1 has no `holders` rows and needs no cleanup.
- `setversion` takes `2.0.0`.
- Signers of an msig proposal check the proposal's wasm sha256 against the table above, and its packed ABI against the published `.abi`, because the chain does not validate `setabi` payloads.

### Features

- `redtemplmax` lowers a template's `max_supply`, never below the supply already issued. `0907db9`
- `deltemplate` removes a template that has no issued assets and erases its `templates2` row. `0907db9`
- `createtempl2` creates a template that carries mutable data and `settempldata` updates it, each change emitting `logsetdatatl`. The mutable data lives in the new `templates2` table beside the immutable `templates` row, so a reader that knows only `templates` still works. `0907db9`
- `setschematyp` records per-field media-type descriptors for a schema in the new `schematypes` table, so a consumer can tell how to render a field instead of inferring it from the field name. The action replaces the whole descriptor array, so a client reads the stored descriptors before it writes, or it writes its own inferred view back to chain. `0907db9`
- `createauswap` proposes a new collection author and `acceptauswap` or `rejectauswap` completes or cancels the handover, with pending swaps in the new `authorswaps` table. The collection's `author` changes only on acceptance, so no single party moves a collection on its own. `0907db9`
- `setrampayer` and `setlastpayer` reassign an asset's RAM payer and emit `logrampayer`. `setrampayer` moves a named asset to the caller and refunds the previous payer, and `setlastpayer` does the same for the caller's newest asset in a collection. (#19)
- The collection-authorization path reads only the bytes it needs from the collection row through a low-level partial read, instead of loading a row that can carry several KB of serialized data on every schema, template and asset action. The transfer and offer paths also stop building their failure message on the success path, since `check(cond, msg)` evaluates the message before the call. `89774e9`

### Other changes

- Custodial rentals are not part of v2. The implementation is preserved on the [`archive/v2-custodial-rentals`](https://github.com/atomicassets/atomicassets-contract/tree/archive/v2-custodial-rentals) branch. (#27)
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ $ make clean
$ make build
```

## Releases

Tagged versions are published as GitHub Releases with the `atomicassets.wasm`,
`atomicassets.abi` and `SHA256SUMS` assets attached.
[RELEASING.md](RELEASING.md) covers how a release is cut and what its notes
carry, and [CHANGELOG.md](CHANGELOG.md) holds the notes for each version.

## Testing

### Test Framework
Expand Down Expand Up @@ -91,4 +98,9 @@ Tests are organized in directories by functionality:
- `tests/interface-header/` - Interface header consumer compile check
- `tests/schema-actions/` - Schema operations
- `tests/template-actions/` - Template management
- `tests/transfer-offer-actions/` - Transfer and trading functionality
- `tests/transfer-offer-actions/` - Transfer and trading functionality

## Credits

AtomicAssets is the work of many contributors, recorded in
[AUTHORS.md](AUTHORS.md).
222 changes: 222 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# Releasing atomicassets-contract

How a version of this contract reaches GitHub Releases. A release ends at a
rendered Release carrying `atomicassets.wasm`, `atomicassets.abi` and
`SHA256SUMS` as assets, not at the pushed tag: those checksums are what a
deployer pins and what a signer of a multi-party proposal verifies against.

Tags are `vX.Y.Z` (`v2.0.0`), and a release candidate is `vX.Y.Z-rcN`
(`v2.0.0-rc5`). The release artifacts are built with the CDT version CI pins,
4.1.1, so a reader can rebuild the tag and get the hashes the notes name.

## Checklist

1. The feature PR carries the `CHANGELOG.md` entry for the version under
`## [X.Y.Z]`, written in the section shape below with H3 headings. Its
`### Upgrading` states the ABI compatibility with the previous stable release
(byte-identical, additive, or breaking with the migration a consumer makes)
and the `setversion` value, which is the core semver of the tag. The rows of
the checksum table are left empty here, because the build in step 2 produces
them. The entry is the editorial text of the Release, so it is written once,
in the PR that makes the change.

2. Build the release artifacts from a clean tree and write the checksum file:

```sh
make clean
make release
(cd build && sha256sum atomicassets.wasm atomicassets.abi) > SHA256SUMS
```

`make release` compiles with the pinned CDT and patches the ABI back to the
legacy spellings, which is what the released `.abi` carries. This
repository has no docker build path, so the release build needs the CDT
that CI installs (`CDT_VERSION` in `.github/workflows/contracts-ci.yaml`)
installed natively. The checksum file uses bare asset names, so it verifies
against the downloaded assets in step 6. Copy its two rows into the entry's
`### Upgrading` table:

```
| Asset | sha256 |
| --- | --- |
| `atomicassets.wasm` | `<sha256>` |
| `atomicassets.abi` | `<sha256>` |
```

Land that as a `chore(release): X.Y.Z` commit touching `CHANGELOG.md`
alone. The wasm and the ABI do not depend on `CHANGELOG.md`, so a build of
the tag reproduces the hashes the entry names. `SHA256SUMS` is a release
asset rather than a committed file, and it stays out of the commit. A
stable release that ships the last candidate's build has identical rows
already in the entry: tag the candidate's commit and land nothing new.

3. Preview the body before anything is tagged:

```sh
scripts/release-notes.sh vX.Y.Z main
```

The preview composes the body from the `CHANGELOG.md` entry at that branch
and the commits since the previous tag, and it fails when the entry is
missing. It does not check the section names, so read the preview against
the template below. Pass `origin/main` in a clone without a local `main`.
The compare link is built from the `origin` remote, so cut the release from
a clone whose `origin` is this repository, not a fork.

4. Tag the release commit and push the tag:

```sh
git tag vX.Y.Z && git push origin vX.Y.Z
```

A candidate is tagged `vX.Y.Z-rcN`. Push the tag before creating the
Release, because `--verify-tag` refuses a tag the remote does not have.

5. Compose the body, read it, then create the Release with its assets:

```sh
scripts/release-notes.sh vX.Y.Z > notes.md
gh release create vX.Y.Z --verify-tag --title vX.Y.Z --notes-file notes.md \
build/atomicassets.wasm build/atomicassets.abi SHA256SUMS
```

Add `--prerelease` for a `-rcN` tag, so the candidate does not become the
repository's latest Release. Add `--latest=false` when the Release is for a
tag older than the current latest one, so the latest marker does not move
backwards. With more than one release in flight, create them in ascending
version order.

6. Verify the published Release against its own assets:

```sh
gh release download vX.Y.Z --dir /tmp/vX.Y.Z
(cd /tmp/vX.Y.Z && sha256sum -c SHA256SUMS)
```

The body's table names the same two hashes. When either check fails, never
re-attach an asset and never move the tag on a published Release: a
consumer that pinned these hashes fails closed on any change, and a signer
may already have verified a proposal against them. Cut the next patch
version instead.

Deploying the contract, whether by key or by multi-party proposal, and the
`setcode`, `setabi`, `setversion` and resource steps that go with it, stays with
the deployer's own procedure. The Release is what they pin and verify against.

## Body template

The Release title is the tag name verbatim. The body is an optional
one-sentence summary, then the sections that have items, then the commit list,
then the compare link as the last line. Nothing follows the link, and a section
with no items is left out.

```
<one-sentence summary, optional>

## Breaking changes

- <what changed, and what the reader does about it>. (#N)

## Upgrading

- <what the move from the previous stable release takes: the checksums, the ABI compatibility, the setversion value>.

## Features

- <what is new>. (#N)

## Bug fixes

- <what was wrong and is not now>. (#N)

## Security

- <the advisory or the dependency lift, named>. (#N)

## Deprecations

- <what is deprecated and what replaces it>. (#N)

## Other changes

- <a change a consumer notices that fits no section above>. (#N)

## Commits

- <short sha> <subject>

Full changelog: https://github.com/atomicassets/atomicassets-contract/compare/<PREV>...<TAG>
```

The section order is breaking changes, upgrading, features, bug fixes,
security, deprecations, other changes.

A Release body carries no credits section. Contributor and lineage credit lives
in [AUTHORS.md](./AUTHORS.md) and the README, where it is maintained once
rather than restated per version.

`## Upgrading` is for the deployer and the integrator, and it is written against
the previous stable release rather than against the tag range the commit list
covers. For this contract it carries the checksum table of the released wasm and
ABI, the statement of how the ABI compares with the previous stable release
(byte-identical, additive, or breaking with the migration a consumer makes), the
`setversion` value, and any ordering or resource note the deploy depends on. A
candidate body may confine it to the change since the previous candidate that
has a Release, because that is the move a test deployment makes; the stable body
describes the whole move. One table is allowed here, and it lists the released
artifact checksums. Items elsewhere stay bullets.

`## Security` carries advisories and dependency lifts, each naming its GHSA or
CVE identifier. A release with neither section leaves both out.

## Voice

- Neutral and factual, the register of the Node.js or esbuild release notes.
- Sectioned. The heading says what kind of change it is, so the item does not
repeat it.
- One to three plain sentences per item: what changed, and what the reader does
about it when action is needed. Code identifiers in backticks.
- Every item ends with its PR reference `(#N)`, or with its short sha in
backticks when the change had no PR. An `## Upgrading` item that states a
deploy fact rather than a change, such as a checksum or an ABI that has not
moved, carries no reference.
- No preface, no motivation essay, no clause chain explaining how the author got
there. The why stays only where it changes what the reader does.
- Present tense for the new behavior, sentence-case headings, straight quotes,
and no em-dash.

## The CHANGELOG entry

`CHANGELOG.md` is where the editorial text is written, and the Release body is
that entry with its headings promoted one level.

An entry heading is `## [X.Y.Z]`, optionally followed by ` - YYYY-MM-DD`. Under
it comes an optional one-line summary, then the H3 sections in the order above
(`### Breaking changes`, `### Upgrading`, and the rest). A candidate tag
`vX.Y.Z-rcN` reads the `## [X.Y.Z]` entry as it stands at that tag, so a
candidate body shows the notes for the version so far and the stable body shows
the finished entry.

## Tag ranges, candidates, and older releases

- `PREV` for a stable tag is the nearest earlier stable `v*` tag, so a stable
release lists every commit since the last stable release and skips the
candidates between them. `PREV` for a candidate tag is the nearest earlier tag
of any kind, which is usually the previous candidate. A stable tag whose only
earlier tags are candidates takes the nearest of them, so the first stable
release after a candidate line lists what it adds to the last candidate.
- Tags from the upstream v1 line count as earlier tags, so `v2.0.0` lists the
commits since `v1.2.3`. Those v1 tags carry no Release of their own.
- `## Commits` lists the whole `PREV..TAG` range, oldest first, including the
release commit. Its line count equals `git rev-list --count PREV..TAG`.
- A tag with no earlier tag has no `PREV`. Its body is the summary and the
sentence `Initial release.`, with no commit list and no compare link, and it
is written by hand.
- A candidate tag is created with `--prerelease`, and a Release created for a
tag older than the current latest is created with `--latest=false`.

`scripts/release-notes.sh` needs bash, git, awk and sed. Without a ref it reads
`CHANGELOG.md` at the tag rather than from the working tree, so the body
describes what the tag ships. It exits non-zero and names what is missing when
no tag is given, when the tag does not exist, when the CHANGELOG at that ref
carries no entry for the version, and when no earlier tag exists.
Loading
Loading