@bannynet/core-v6 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADMINISTRATION.md +60 -109
- package/ARCHITECTURE.md +69 -44
- package/AUDIT_INSTRUCTIONS.md +45 -57
- package/README.md +44 -2
- package/SKILLS.md +5 -3
- package/USER_JOURNEYS.md +128 -39
- package/foundry.toml +2 -0
- package/package.json +35 -35
- package/references/operations.md +2 -2
- package/references/runtime.md +1 -1
- package/src/Banny721TokenUriResolver.sol +0 -5
package/ADMINISTRATION.md
CHANGED
|
@@ -1,136 +1,87 @@
|
|
|
1
1
|
# Administration
|
|
2
2
|
|
|
3
|
-
Admin privileges and their scope in banny-retail-v6. The contract (`Banny721TokenUriResolver`) is a single-file system with one admin role (Ownable) and per-token owner privileges.
|
|
4
|
-
|
|
5
3
|
## At A Glance
|
|
6
4
|
|
|
7
5
|
| Item | Details |
|
|
8
|
-
|
|
9
|
-
| Scope |
|
|
10
|
-
|
|
|
11
|
-
| Highest-risk actions |
|
|
12
|
-
| Recovery posture |
|
|
13
|
-
|
|
14
|
-
## Routine Operations
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Scope | `Banny721TokenUriResolver` metadata, SVG commitments, and outfit-state control |
|
|
8
|
+
| Control posture | Global `Ownable` metadata control plus per-body owner control |
|
|
9
|
+
| Highest-risk actions | Wrong SVG hash commitments, incorrect metadata updates, and long outfit locks |
|
|
10
|
+
| Recovery posture | Metadata is editable, but committed hashes, uploaded SVGs, and active locks are not reversible |
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
- Treat metadata and product-name changes as ecosystem-wide display changes that affect every token rendered through the resolver.
|
|
18
|
-
- Remind users that equipped assets are held by the resolver contract until they are unequipped through the supported flow.
|
|
19
|
-
- Use outfit locks deliberately, because they freeze body-level changes for the fixed lock window.
|
|
12
|
+
## Purpose
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
`banny-retail-v6` has a small but real control plane. The resolver owner controls collection-wide metadata and SVG commitments. Body owners control decoration and outfit locks. No admin can rescue equipped NFTs from custody if resolver logic fails.
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
- `setSvgContentsOf` is also write-once once valid content is uploaded.
|
|
25
|
-
- `lockOutfitChangesFor` can only extend the active lock, never shorten it.
|
|
26
|
-
- There is no admin rescue path for custodially held outfit NFTs.
|
|
16
|
+
## Control Model
|
|
27
17
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
18
|
+
- `Banny721TokenUriResolver` is `Ownable`.
|
|
19
|
+
- Global admin power is limited to metadata, product naming, and SVG hash commitments.
|
|
20
|
+
- Actual SVG payload upload is permissionless once the hash is committed.
|
|
21
|
+
- Body owners control decoration and locking for their own bodies.
|
|
22
|
+
- Equipped accessories are held custodially by the resolver while attached.
|
|
32
23
|
|
|
33
24
|
## Roles
|
|
34
25
|
|
|
35
|
-
| Role | How Assigned | Scope |
|
|
36
|
-
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
| **Anyone (Permissionless)** | No restriction. | Upload SVG content (if matching hash exists) |
|
|
41
|
-
| **Trusted Forwarder** | Set at construction via `ERC2771Context(trustedForwarder)`. Immutable after deploy. | Meta-transaction relay: `_msgSender()` resolves to the relayed sender |
|
|
42
|
-
|
|
43
|
-
## Privileged Functions
|
|
44
|
-
|
|
45
|
-
### Banny721TokenUriResolver -- Owner-Only Functions
|
|
46
|
-
|
|
47
|
-
| Function | Guard | What It Does |
|
|
48
|
-
|----------|-------|-------------|
|
|
49
|
-
| `setMetadata(description, url, baseUri)` | `onlyOwner` | Overwrites the token metadata description, external URL, and SVG base URI. All three fields are always written (pass current value to keep, empty string to clear). |
|
|
50
|
-
| `setProductNames(upcs, names)` | `onlyOwner` | Sets custom display names for products identified by UPC. Names are stored in `_customProductNameOf` mapping. Can overwrite previously set names. |
|
|
51
|
-
| `setSvgHashesOf(upcs, svgHashes)` | `onlyOwner` | Commits keccak256 hashes for SVG content keyed by UPC. Each hash can only be set once -- reverts with `HashAlreadyStored` if the UPC already has a hash. This is the gating step that controls which SVG content can later be uploaded permissionlessly. |
|
|
52
|
-
|
|
53
|
-
### Banny721TokenUriResolver -- Permissionless Functions
|
|
54
|
-
|
|
55
|
-
| Function | Guard | What It Does |
|
|
56
|
-
|----------|-------|-------------|
|
|
57
|
-
| `setSvgContentsOf(upcs, svgContents)` | None (anyone) | Stores SVG content for a UPC, but only if: (1) a hash was previously committed by the owner via `setSvgHashesOf`, (2) `keccak256(content) == storedHash`, and (3) content has not already been stored (`ContentsAlreadyStored`). This is the permissionless "lazy upload" mechanism. |
|
|
26
|
+
| Role | How Assigned | Scope | Notes |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| Resolver owner | `Ownable(owner)` at construction | Global | Can transfer ownership with OpenZeppelin `transferOwnership()` |
|
|
29
|
+
| Body owner | `IERC721(hook).ownerOf(bannyBodyId)` | Per body | Can decorate and lock that body |
|
|
30
|
+
| Anyone | No assignment | Global | Can upload SVG bytes only if they match a committed hash |
|
|
58
31
|
|
|
59
|
-
|
|
32
|
+
## Privileged Surfaces
|
|
60
33
|
|
|
61
|
-
|
|
|
62
|
-
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
34
|
+
| Contract | Function | Who Can Call | Effect |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| `Banny721TokenUriResolver` | `setMetadata(...)` | Resolver owner | Changes global description, URL, and base URI |
|
|
37
|
+
| `Banny721TokenUriResolver` | `setProductNames(...)` | Resolver owner | Changes display names for products |
|
|
38
|
+
| `Banny721TokenUriResolver` | `setSvgHashesOf(...)` | Resolver owner | Commits write-once SVG hashes for UPCs |
|
|
39
|
+
| `Banny721TokenUriResolver` | `setSvgContentsOf(...)` | Anyone with matching bytes | Uploads write-once SVG payloads for committed hashes |
|
|
40
|
+
| `Banny721TokenUriResolver` | `decorateBannyWith(...)` | Current body owner | Equips or unequips accessories and updates custody |
|
|
41
|
+
| `Banny721TokenUriResolver` | `lockOutfitChangesFor(...)` | Current body owner | Extends the outfit lock window for that body |
|
|
65
42
|
|
|
66
|
-
|
|
43
|
+
## Immutable And One-Way
|
|
67
44
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
45
|
+
- SVG hash commitments are write-once.
|
|
46
|
+
- SVG contents are write-once once uploaded.
|
|
47
|
+
- `lockOutfitChangesFor(...)` only extends the active lock; it never shortens it.
|
|
48
|
+
- The lock duration is fixed by the `_LOCK_DURATION` constant.
|
|
49
|
+
- Default art fragments, category semantics, and the trusted forwarder are constructor or code immutables.
|
|
71
50
|
|
|
72
|
-
##
|
|
51
|
+
## Operational Notes
|
|
73
52
|
|
|
74
|
-
|
|
53
|
+
- Treat `setSvgHashesOf(...)` like a release gate. A wrong hash usually means new resolver or new UPC strategy, not an edit.
|
|
54
|
+
- Treat `setMetadata(...)` and `setProductNames(...)` as collection-wide display changes.
|
|
55
|
+
- Remind users that equipped assets are in resolver custody while attached.
|
|
56
|
+
- Only lock outfits when temporary non-editability is the intended user experience.
|
|
57
|
+
- Use safe ERC-721 transfer flows when assets are sent into the resolver path; plain `transferFrom` can bypass receiver checks and strand NFTs without a recovery path.
|
|
75
58
|
|
|
76
|
-
|
|
77
|
-
2. **Anyone** can then upload the actual SVG content via `setSvgContentsOf()`, provided the content's keccak256 hash matches the owner-committed hash. This is intentional: the owner sets the commitment, and anyone can fulfill it (useful for gas-efficient lazy uploading).
|
|
59
|
+
## Machine Notes
|
|
78
60
|
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
61
|
+
- Do not infer a rescue path for equipped assets; there is none in this contract.
|
|
62
|
+
- Treat `src/Banny721TokenUriResolver.sol` as the source of truth for lock extension and write-once SVG behavior.
|
|
63
|
+
- If a committed hash and intended asset bytes differ, stop; the contract does not support overwrite repair.
|
|
64
|
+
- If an asset arrived through non-safe ERC-721 transfer semantics, do not assume the resolver can detect or recover it.
|
|
83
65
|
|
|
84
|
-
|
|
85
|
-
- Can be overwritten by the owner at any time via `setProductNames()`. There is no immutability guard on names -- the owner can rename products freely. The built-in names for UPCs 1-4 (Alien, Pink, Orange, Original) are hardcoded in `_productNameOf()` and cannot be overridden.
|
|
66
|
+
## Recovery
|
|
86
67
|
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
When a user equips an outfit or background on a banny body via `decorateBannyWith()`, the outfit/background NFT is transferred from the user's wallet into the `Banny721TokenUriResolver` contract. The resolver holds these NFTs in custody until the user unequips them (by calling `decorateBannyWith()` again with different outfits).
|
|
93
|
-
|
|
94
|
-
**Trust assumptions:**
|
|
95
|
-
- Users must trust that the resolver contract's `decorateBannyWith()` function correctly returns NFTs when outfits are changed. There is no separate `withdraw()` or `rescue()` function.
|
|
96
|
-
- The `onERC721Received` guard (`operator == address(this)`) prevents anyone from sending arbitrary NFTs to the resolver. Only self-initiated transfers during `decorateBannyWith()` are accepted.
|
|
97
|
-
- If the banny body NFT is transferred to a new owner while outfits are equipped, the new body owner can unequip and claim the outfit NFTs (the ownership check in `_checkIfSenderIsOwner` is against the current body owner).
|
|
98
|
-
- The `lockOutfitChangesFor()` function can lock outfits for up to 7 days per call (extendable). During a lock, neither the body owner nor anyone else can change the equipped outfits.
|
|
99
|
-
- There is no admin override to rescue stuck outfit NFTs. If a bug in `decorateBannyWith()` prevents unequipping, the outfits remain locked in the resolver permanently.
|
|
100
|
-
|
|
101
|
-
## Immutable Configuration
|
|
102
|
-
|
|
103
|
-
The following are set at construction and cannot be changed:
|
|
104
|
-
|
|
105
|
-
| Property | Set At | Value |
|
|
106
|
-
|----------|--------|-------|
|
|
107
|
-
| `BANNY_BODY` | Constructor | Base SVG path for all banny body rendering |
|
|
108
|
-
| `DEFAULT_NECKLACE` | Constructor | Default necklace SVG injected when no custom necklace equipped |
|
|
109
|
-
| `DEFAULT_MOUTH` | Constructor | Default mouth SVG injected when no custom mouth equipped |
|
|
110
|
-
| `DEFAULT_STANDARD_EYES` | Constructor | Default eyes SVG for non-alien bodies |
|
|
111
|
-
| `DEFAULT_ALIEN_EYES` | Constructor | Default eyes SVG for alien bodies |
|
|
112
|
-
| `trustedForwarder` | Constructor | ERC-2771 forwarder address for meta-transactions |
|
|
113
|
-
| `_LOCK_DURATION` | Constant | 7 days -- hardcoded, not configurable |
|
|
114
|
-
| Body color fills | Hardcoded in `_fillsFor()` | Color palettes for Alien, Pink, Orange, Original body types |
|
|
115
|
-
| Category IDs | Constants | 18 category slots (0-17), hardcoded |
|
|
68
|
+
- Bad metadata can be changed by the owner.
|
|
69
|
+
- Bad SVG commitments or uploaded content cannot be corrected in place.
|
|
70
|
+
- If equipped assets become stuck because of resolver logic, there is no owner rescue path in this contract.
|
|
71
|
+
- If NFTs are stranded through non-safe transfer semantics, this contract does not provide a recovery flow.
|
|
116
72
|
|
|
117
73
|
## Admin Boundaries
|
|
118
74
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
- **Cannot change the lock duration.** The 7-day lock is a compile-time constant.
|
|
125
|
-
- **Cannot force-equip or force-unequip outfits.** Only the body NFT's owner can call `decorateBannyWith` and `lockOutfitChangesFor`.
|
|
126
|
-
- **Cannot override hardcoded body names.** UPCs 1-4 always resolve to Alien, Pink, Orange, Original regardless of `_customProductNameOf`.
|
|
127
|
-
- **Cannot change the trusted forwarder.** It is immutable after construction.
|
|
128
|
-
- **Cannot pause the contract.** There is no pause mechanism.
|
|
129
|
-
- **Cannot upgrade the contract.** It is not upgradeable.
|
|
75
|
+
- The owner cannot withdraw equipped user NFTs arbitrarily.
|
|
76
|
+
- The owner cannot overwrite committed hashes or uploaded SVG contents.
|
|
77
|
+
- The owner cannot bypass body-owner checks on decoration or locking.
|
|
78
|
+
- Nobody can shorten an active outfit lock.
|
|
79
|
+
- There is no pause, upgrade, or rescue mechanism.
|
|
130
80
|
|
|
131
|
-
|
|
81
|
+
## Source Map
|
|
132
82
|
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
83
|
+
- `src/Banny721TokenUriResolver.sol`
|
|
84
|
+
- `src/interfaces/IBanny721TokenUriResolver.sol`
|
|
85
|
+
- `script/Deploy.s.sol`
|
|
86
|
+
- `test/TestAuditGaps.sol`
|
|
87
|
+
- `test/TestQALastMile.t.sol`
|
package/ARCHITECTURE.md
CHANGED
|
@@ -2,75 +2,100 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
`banny-retail-v6`
|
|
5
|
+
`banny-retail-v6` is the Banny-specific metadata and attachment layer for Juicebox 721 collections. It does not mint the NFTs or own treasury logic. It owns attachment custody, outfit-lock rules, and final token rendering.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## System Overview
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- `nana-721-hook-v6` still owns token minting, transfers, and collection-level ERC-721 behavior.
|
|
11
|
-
- The resolver is intentionally application-specific. Generic 721 hook behavior should stay in `nana-721-hook-v6`.
|
|
9
|
+
The repo is centered on `Banny721TokenUriResolver`. A 721 hook from `nana-721-hook-v6` points to this resolver for `tokenURI(...)`, while bodies, outfits, and backgrounds remain separate NFTs at the collection layer. The resolver escrows equipped accessories, records which assets are attached to each body, and composes the final SVG and JSON metadata on demand.
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Core Invariants
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
- A body can only reference accessories that are currently escrowed by the resolver.
|
|
14
|
+
- Replacing an equipped item must atomically return the old item and escrow the new item.
|
|
15
|
+
- Outfit locks must block both explicit removal and implicit replacement until the lock expires.
|
|
16
|
+
- Equipped assets travel with the body NFT on transfer until the new owner unequips them.
|
|
17
|
+
- Registered SVG payloads must match their pre-registered content hash before they become renderable.
|
|
18
|
+
- Rendering must stay deterministic for the same stored body state.
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Modules
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
| Module | Responsibility | Notes |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `Banny721TokenUriResolver` | Escrow, attachment state, lock windows, and metadata rendering | Main contract; application-specific |
|
|
25
|
+
| `IBanny721TokenUriResolver` | External integration surface | Used by hooks and offchain tooling |
|
|
26
|
+
|
|
27
|
+
## Trust Boundaries
|
|
28
|
+
|
|
29
|
+
- Minting, ownership transfer, and collection-level ERC-721 semantics live in `nana-721-hook-v6`.
|
|
30
|
+
- This repo is trusted for rendering correctness and custody of equipped assets.
|
|
31
|
+
- Asset content upload is controlled by the registered content owner, but the contract verifies the uploaded bytes against the stored hash.
|
|
32
|
+
|
|
33
|
+
## Critical Flows
|
|
34
|
+
|
|
35
|
+
### Decorate
|
|
23
36
|
|
|
24
37
|
```text
|
|
25
38
|
body owner
|
|
26
39
|
-> calls decorateBannyWith(...)
|
|
27
|
-
-> resolver verifies ownership
|
|
28
|
-
-> resolver pulls
|
|
29
|
-
-> resolver
|
|
30
|
-
-> resolver returns
|
|
40
|
+
-> resolver verifies body ownership and lock status
|
|
41
|
+
-> resolver pulls new accessories into escrow
|
|
42
|
+
-> resolver updates equipped slots
|
|
43
|
+
-> resolver returns replaced accessories to the owner
|
|
31
44
|
```
|
|
32
45
|
|
|
33
|
-
###
|
|
46
|
+
### Render
|
|
34
47
|
|
|
35
48
|
```text
|
|
36
49
|
tokenURI(bodyId)
|
|
37
|
-
->
|
|
38
|
-
->
|
|
39
|
-
->
|
|
40
|
-
->
|
|
50
|
+
-> resolver loads body, background, and equipped slot state
|
|
51
|
+
-> fetches registered SVG fragments
|
|
52
|
+
-> composes layered SVG in Banny-specific order
|
|
53
|
+
-> returns base64 JSON metadata
|
|
41
54
|
```
|
|
42
55
|
|
|
43
|
-
###
|
|
56
|
+
### Lock Outfit
|
|
44
57
|
|
|
45
58
|
```text
|
|
46
|
-
owner
|
|
47
|
-
-> lockOutfitChangesFor(...)
|
|
48
|
-
->
|
|
49
|
-
-> decoration and removal paths must respect
|
|
59
|
+
body owner
|
|
60
|
+
-> calls lockOutfitChangesFor(...)
|
|
61
|
+
-> resolver stores a no-change window
|
|
62
|
+
-> later decoration and removal paths must respect it
|
|
50
63
|
```
|
|
51
64
|
|
|
52
|
-
##
|
|
65
|
+
## Accounting Model
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
- Slot replacement must be one-for-one. Replacing an equipped item returns the old item instead of orphaning it.
|
|
56
|
-
- Outfit locks must block both direct edits and indirect attempts to reclaim an equipped item through another decoration call.
|
|
57
|
-
- Asset registration is split between hash registration and content upload so content can be trustlessly verified before it is stored on-chain.
|
|
67
|
+
This repo does not own treasury accounting. Its critical state is custody accounting: which NFTs are escrowed, which body they belong to, and when a body is locked against changes.
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
That custody model uses lazy reconciliation for some stale attachment records. Read paths filter against current ownership and attachment state instead of eagerly rewriting storage on every external transfer.
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
- Lock enforcement has to cover both explicit removal and implicit replacement paths.
|
|
63
|
-
- SVG composition order is application logic, not a cosmetic detail.
|
|
71
|
+
## Security Model
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
73
|
+
- The main failure mode is custody drift between slot state and actual escrowed NFTs.
|
|
74
|
+
- Rendering order is part of application semantics, not cosmetic output.
|
|
75
|
+
- Lazy reconciliation is intentional. Changes that assume attachment arrays are perfectly clean in storage can strand assets or mis-render bodies.
|
|
76
|
+
- Any new asset category adds both a rendering concern and a custody concern.
|
|
69
77
|
|
|
70
78
|
## Safe Change Guide
|
|
71
79
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
- If
|
|
76
|
-
- If
|
|
80
|
+
- Keep generic ERC-721 behavior in `nana-721-hook-v6`, not here.
|
|
81
|
+
- Review escrow writes and transfer behavior together whenever changing attachment logic.
|
|
82
|
+
- If transfer or cleanup behavior changes, re-check lazy reconciliation assumptions alongside body-transfer inheritance of equipped assets.
|
|
83
|
+
- If `tokenURI(...)` changes, test stable output for unchanged state and replacement behavior for changed state.
|
|
84
|
+
- If adding slots or asset classes, update rendering order, slot replacement, and lock enforcement in one change.
|
|
85
|
+
|
|
86
|
+
## Canonical Checks
|
|
87
|
+
|
|
88
|
+
- accessory escrow, replacement, and decoration flow:
|
|
89
|
+
`test/DecorateFlow.t.sol`
|
|
90
|
+
- burned-body custody edge cases:
|
|
91
|
+
`test/audit/BurnedBodyStrandsAssets.t.sol`
|
|
92
|
+
- transfer-path protection against stranded attachments:
|
|
93
|
+
`test/audit/TryTransferFromStrandsAssets.t.sol`
|
|
94
|
+
|
|
95
|
+
## Source Map
|
|
96
|
+
|
|
97
|
+
- `src/Banny721TokenUriResolver.sol`
|
|
98
|
+
- `test/DecorateFlow.t.sol`
|
|
99
|
+
- `test/audit/BurnedBodyStrandsAssets.t.sol`
|
|
100
|
+
- `test/audit/TryTransferFromStrandsAssets.t.sol`
|
|
101
|
+
- `script/Deploy.s.sol`
|
package/AUDIT_INSTRUCTIONS.md
CHANGED
|
@@ -1,87 +1,75 @@
|
|
|
1
1
|
# Audit Instructions
|
|
2
2
|
|
|
3
|
-
This repo is the Banny avatar composition layer.
|
|
3
|
+
This repo is the Banny avatar composition layer. It does not mint the base NFTs, but it does custody equipped accessories and define the metadata users see.
|
|
4
4
|
|
|
5
|
-
## Objective
|
|
5
|
+
## Audit Objective
|
|
6
6
|
|
|
7
7
|
Find issues that:
|
|
8
|
-
- strand
|
|
9
|
-
- let the wrong actor equip, unequip,
|
|
10
|
-
-
|
|
11
|
-
- return
|
|
12
|
-
-
|
|
8
|
+
- strand outfits or backgrounds in resolver custody
|
|
9
|
+
- let the wrong actor equip, unequip, overwrite, or recover accessories
|
|
10
|
+
- break outfit-lock timing or freeze a body longer than intended
|
|
11
|
+
- return metadata that does not match stored attachment state
|
|
12
|
+
- bypass category or layering constraints
|
|
13
13
|
|
|
14
14
|
## Scope
|
|
15
15
|
|
|
16
16
|
In scope:
|
|
17
17
|
- `src/Banny721TokenUriResolver.sol`
|
|
18
18
|
- `src/interfaces/IBanny721TokenUriResolver.sol`
|
|
19
|
-
- deployment
|
|
19
|
+
- all deployment helpers in `script/`
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
- the resolver is used as a token URI resolver for a `JB721TiersHook`
|
|
23
|
-
- the underlying 721 hook remains the token contract and tier source
|
|
24
|
-
- the resolver temporarily holds accessory NFTs while they are equipped
|
|
21
|
+
## Start Here
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
1. `src/Banny721TokenUriResolver.sol`
|
|
24
|
+
2. accessory receipt and release paths
|
|
25
|
+
3. deployment wiring in `script/`
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
- reads tier and token metadata from the attached 721 hook
|
|
30
|
-
- receives outfit and background NFTs through safe transfers
|
|
31
|
-
- records which body currently has which attachments
|
|
32
|
-
- enforces category and conflict rules
|
|
33
|
-
- renders composed metadata and SVG output
|
|
27
|
+
## Security Model
|
|
34
28
|
|
|
35
|
-
The
|
|
36
|
-
-
|
|
37
|
-
- resolver holds equipped
|
|
38
|
-
-
|
|
29
|
+
The resolver is an attachment and rendering layer around a `JB721TiersHook` collection.
|
|
30
|
+
- the underlying 721 hook remains the token contract and source of body ownership
|
|
31
|
+
- the resolver temporarily holds accessory NFTs while they are equipped
|
|
32
|
+
- body ownership should be the only authority that changes equipped state
|
|
33
|
+
- accessory contracts may be hostile or malformed, so receipt and release ordering matters
|
|
39
34
|
|
|
40
|
-
##
|
|
35
|
+
## Roles And Privileges
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
| Role | Powers | How constrained |
|
|
38
|
+
|------|--------|-----------------|
|
|
39
|
+
| Body owner | Equip, unequip, and lock accessories | Must be derived from the current hook-reported owner |
|
|
40
|
+
| Resolver owner | Update metadata and SVG-related admin state | Must not control equipped-state authorization |
|
|
41
|
+
| Accessory NFT contract | Execute callbacks during custody changes | Must not corrupt bookkeeping or steal custody |
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
Only an authorized actor for the body may change its equipped state.
|
|
43
|
+
## Integration Assumptions
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
| Dependency | Assumption | What breaks if wrong |
|
|
46
|
+
|------------|------------|----------------------|
|
|
47
|
+
| `JB721TiersHook` | Reports authentic body ownership and tier metadata | Unauthorized decoration or incorrect rendering |
|
|
48
|
+
| Accessory ERC-721s | Behave like standard transferable NFTs | Custody or release flows fail unexpectedly |
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
`lockOutfitChangesFor` must only prevent changes for the intended body and duration. It must not be bypassable, extendable by unauthorized actors, or accidentally permanent.
|
|
50
|
+
## Critical Invariants
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
1. Every accessory transferred into the resolver remains attributable to one body or is recoverable by the rightful owner.
|
|
53
|
+
2. Only the current body owner or an intended delegate can change that body's equipped state.
|
|
54
|
+
3. Conflicting categories cannot be equipped together, including through replacement or invalidation edge paths.
|
|
55
|
+
4. Outfit-lock state only affects the intended body for the intended duration.
|
|
56
|
+
5. Metadata and SVG generation reflect current state and do not expose impossible combinations.
|
|
56
57
|
|
|
57
|
-
##
|
|
58
|
+
## Attack Surfaces
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
- attempt to steal accessories by redecorating around lock windows
|
|
60
|
+
- decoration entrypoints that replace one accessory with another
|
|
61
|
+
- ERC-721 receipt hooks and any path that accepts custody
|
|
62
|
+
- release paths after redecorating, burning, or invalid token state
|
|
63
|
+
- category validation and conflict checks
|
|
64
|
+
- metadata assembly that assumes on-chain assets or tier data remain available
|
|
65
65
|
|
|
66
|
-
##
|
|
66
|
+
## Accepted Risks Or Behaviors
|
|
67
67
|
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
- outfit/background release paths after redecorating, burning, or invalid token states
|
|
71
|
-
- category validation and conflict checks
|
|
72
|
-
- lock timestamp handling
|
|
73
|
-
- token URI generation that assumes on-chain SVG data exists or remains consistent
|
|
68
|
+
- Equipped accessories intentionally follow the body unless they are unequipped first.
|
|
69
|
+
- Preserving attribution on failed transfer-out is safer than dropping custody state.
|
|
74
70
|
|
|
75
|
-
##
|
|
71
|
+
## Verification
|
|
76
72
|
|
|
77
|
-
Standard workflow:
|
|
78
73
|
- `npm install`
|
|
79
74
|
- `forge build`
|
|
80
75
|
- `forge test`
|
|
81
|
-
|
|
82
|
-
The current test tree emphasizes:
|
|
83
|
-
- attack and regression coverage around stranding and exclusivity
|
|
84
|
-
- decoration lifecycle flows
|
|
85
|
-
- fork and QA scenarios
|
|
86
|
-
|
|
87
|
-
Prefer proofs that show a body or accessory becoming inaccessible, transferable by the wrong party, or rendered inconsistently with stored state.
|
package/README.md
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Banny Retail
|
|
2
2
|
|
|
3
|
-
Banny Retail is an on-chain avatar system for Juicebox 721 collections. A body NFT can wear outfit NFTs, sit on a background NFT, and
|
|
3
|
+
Banny Retail is an on-chain avatar system for Juicebox 721 collections. A body NFT can wear outfit NFTs, sit on a background NFT, and resolve to a base64-encoded JSON token URI whose image field contains an on-chain SVG.
|
|
4
4
|
|
|
5
5
|
Docs: <https://docs.juicebox.money>
|
|
6
|
-
Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
6
|
+
Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
7
|
+
User journeys: [USER_JOURNEYS.md](./USER_JOURNEYS.md)
|
|
8
|
+
Skills: [SKILLS.md](./SKILLS.md)
|
|
9
|
+
Risks: [RISKS.md](./RISKS.md)
|
|
10
|
+
Administration: [ADMINISTRATION.md](./ADMINISTRATION.md)
|
|
11
|
+
Audit instructions: [AUDIT_INSTRUCTIONS.md](./AUDIT_INSTRUCTIONS.md)
|
|
7
12
|
|
|
8
13
|
## Overview
|
|
9
14
|
|
|
@@ -36,6 +41,36 @@ This repo owns three things:
|
|
|
36
41
|
|
|
37
42
|
It does not own mint pricing, tier issuance, or project accounting.
|
|
38
43
|
|
|
44
|
+
## Read These Files First
|
|
45
|
+
|
|
46
|
+
1. `src/Banny721TokenUriResolver.sol`
|
|
47
|
+
2. `test/DecorateFlow.t.sol`
|
|
48
|
+
3. `test/OutfitTransferLifecycle.t.sol`
|
|
49
|
+
4. `nana-721-hook-v6/src/JB721TiersHook.sol` for upstream mint and tier behavior
|
|
50
|
+
|
|
51
|
+
## High-Signal Tests
|
|
52
|
+
|
|
53
|
+
1. `test/DecorateFlow.t.sol`
|
|
54
|
+
2. `test/OutfitTransferLifecycle.t.sol`
|
|
55
|
+
3. `test/audit/BurnedBodyStrandsAssets.t.sol`
|
|
56
|
+
4. `test/audit/TryTransferFromStrandsAssets.t.sol`
|
|
57
|
+
5. `test/TestQALastMile.t.sol`
|
|
58
|
+
|
|
59
|
+
## Integration Traps
|
|
60
|
+
|
|
61
|
+
- the resolver custodies equipped assets, so transfer edge cases matter as much as rendering output
|
|
62
|
+
- transferred bodies carry their equipped assets, so a new body holder can inherit control of those items
|
|
63
|
+
- burned bodies and non-safe transfer patterns can strand expectations around resolver-held assets unless integrations model the attachment lifecycle correctly
|
|
64
|
+
- outfit locks persist across body transfers until expiry, so a new holder can inherit a still-locked body
|
|
65
|
+
- metadata quality depends on lazily uploaded asset payloads, not only on the token state
|
|
66
|
+
- collection logic here assumes a Juicebox 721 hook upstream and should not be read as a generic NFT renderer
|
|
67
|
+
|
|
68
|
+
## Where State Lives
|
|
69
|
+
|
|
70
|
+
- equipped outfit and background state live in `Banny721TokenUriResolver`
|
|
71
|
+
- layer rendering and token URI generation live in the same resolver
|
|
72
|
+
- mint pricing, tier inventory, and treasury behavior live upstream in `nana-721-hook-v6`
|
|
73
|
+
|
|
39
74
|
## Install
|
|
40
75
|
|
|
41
76
|
```bash
|
|
@@ -83,4 +118,11 @@ script/
|
|
|
83
118
|
- attached outfits and backgrounds are custodied by the resolver while equipped
|
|
84
119
|
- outfit locks are fixed-duration and cannot be shortened once set
|
|
85
120
|
- on-chain SVG content is immutable once uploaded for a given registered hash
|
|
121
|
+
- ERC-721 `transferFrom` paths that bypass safe-receive checks can still create asset-tracking surprises around resolver custody
|
|
86
122
|
- rendering quality and metadata correctness depend on the integrity of uploaded SVG assets
|
|
123
|
+
|
|
124
|
+
## For AI Agents
|
|
125
|
+
|
|
126
|
+
- Treat this repo as an application-layer resolver, not as the NFT issuance primitive.
|
|
127
|
+
- Start with `Banny721TokenUriResolver` and the lifecycle tests before summarizing attachment behavior.
|
|
128
|
+
- If the question is about mint economics or tier availability, inspect `nana-721-hook-v6` instead of inferring from this repo.
|
package/SKILLS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Use This File For
|
|
4
4
|
|
|
5
5
|
- Use this file when the task involves Banny outfit attachment, layered SVG rendering, token URI composition, or asset custody and lock behavior.
|
|
6
|
-
- Start here, then
|
|
6
|
+
- Start here, then decide whether the issue is custody state, lock semantics, stored SVG content, or final token-URI composition. Those problems often look similar from the outside.
|
|
7
7
|
|
|
8
8
|
## Read This Next
|
|
9
9
|
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
|---|---|
|
|
12
12
|
| Repo overview and user-facing behavior | [`README.md`](./README.md), [`ARCHITECTURE.md`](./ARCHITECTURE.md) |
|
|
13
13
|
| Resolver implementation | [`src/Banny721TokenUriResolver.sol`](./src/Banny721TokenUriResolver.sol) |
|
|
14
|
+
| Runtime and content-management invariants | [`references/runtime.md`](./references/runtime.md), [`references/operations.md`](./references/operations.md) |
|
|
14
15
|
| Deployment or scripted drops | [`script/Deploy.s.sol`](./script/Deploy.s.sol), [`script/Drop1.s.sol`](./script/Drop1.s.sol), [`script/Add.Denver.s.sol`](./script/Add.Denver.s.sol) |
|
|
15
|
-
| Decoration lifecycle and
|
|
16
|
-
| Adversarial or QA coverage | [`test/BannyAttacks.t.sol`](./test/BannyAttacks.t.sol), [`test/
|
|
16
|
+
| Decoration lifecycle and custody invariants | [`test/DecorateFlow.t.sol`](./test/DecorateFlow.t.sol), [`test/OutfitTransferLifecycle.t.sol`](./test/OutfitTransferLifecycle.t.sol) |
|
|
17
|
+
| Adversarial, fork, or final QA coverage | [`test/BannyAttacks.t.sol`](./test/BannyAttacks.t.sol), [`test/Fork.t.sol`](./test/Fork.t.sol), [`test/TestAuditGaps.sol`](./test/TestAuditGaps.sol), [`test/TestQALastMile.t.sol`](./test/TestQALastMile.t.sol) |
|
|
17
18
|
|
|
18
19
|
## Repo Map
|
|
19
20
|
|
|
@@ -36,5 +37,6 @@ Application-layer token URI resolver for Juicebox 721 collections that lets Bann
|
|
|
36
37
|
|
|
37
38
|
- Start in [`src/Banny721TokenUriResolver.sol`](./src/Banny721TokenUriResolver.sol) for both rendering and attachment behavior. This repo is mostly one contract with several tightly coupled responsibilities.
|
|
38
39
|
- Treat custody, stale attachment cleanup, and lock timing as high-risk. Rendering bugs are visible, but custody bugs are worse.
|
|
40
|
+
- Equipped outfits and backgrounds travel with the body NFT. Treat that inheritance behavior as intentional before calling it a custody bug.
|
|
39
41
|
- When a task mentions minting, pricing, or terminal accounting, verify that the problem is not actually in the upstream 721 hook repo.
|
|
40
42
|
- If you touch SVG or metadata behavior, check whether the issue is in stored content, rendering composition, or the hook-to-resolver integration point before patching.
|
package/USER_JOURNEYS.md
CHANGED
|
@@ -1,78 +1,167 @@
|
|
|
1
1
|
# User Journeys
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Repo Purpose
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
This repo is the Banny-specific composition and metadata layer on top of a Juicebox 721 collection.
|
|
6
|
+
It owns attachment custody, compatibility rules, outfit locks, and rendered token metadata. It does not own tier
|
|
7
|
+
pricing, treasury accounting, or mint eligibility outside the resolver-specific checks.
|
|
8
|
+
|
|
9
|
+
## Primary Actors
|
|
10
|
+
|
|
11
|
+
- collection operators publishing bodies, outfits, backgrounds, and metadata
|
|
12
|
+
- collectors equipping and unequipping avatar pieces
|
|
13
|
+
- auditors reviewing custody, lock, and rendering behavior
|
|
14
|
+
|
|
15
|
+
## Key Surfaces
|
|
16
|
+
|
|
17
|
+
- `Banny721TokenUriResolver`: custody, compatibility, locks, and rendered SVG metadata
|
|
18
|
+
- `decorateBannyWith(...)`: equips outfits and a background to a body and returns no-longer-equipped items when possible
|
|
19
|
+
- `lockOutfitChangesFor(...)`: freezes appearance changes for the fixed lock window
|
|
20
|
+
- `setSvgHashesOf(...)` / `setSvgContentsOf(...)`: publish or repair art payloads
|
|
21
|
+
- `setMetadata(...)` / `setProductNames(...)`: update collection metadata and UPC naming
|
|
8
22
|
|
|
9
23
|
## Journey 1: Mint A Body, Outfit, And Background Set
|
|
10
24
|
|
|
11
|
-
**
|
|
25
|
+
**Actor:** collector.
|
|
26
|
+
|
|
27
|
+
**Intent:** acquire the pieces needed to build a composed Banny.
|
|
28
|
+
|
|
29
|
+
**Preconditions**
|
|
30
|
+
- the Banny collection is live through the 721 hook
|
|
31
|
+
- the required body, outfit, and background tiers exist
|
|
12
32
|
|
|
13
|
-
**
|
|
33
|
+
**Main Flow**
|
|
34
|
+
1. Mint the body, outfit, and background NFTs through the underlying 721 project.
|
|
35
|
+
2. Keep mint pricing and issuance assumptions anchored in the 721 hook, not this repo.
|
|
36
|
+
3. Move to this resolver only once the user actually owns compatible pieces.
|
|
14
37
|
|
|
15
|
-
**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
38
|
+
**Failure Modes**
|
|
39
|
+
- the wrong tiers are minted or the pieces are not compatible
|
|
40
|
+
- teams misread this repo as the minting or accounting surface
|
|
41
|
+
|
|
42
|
+
**Postconditions**
|
|
43
|
+
- the user holds the components needed for later composition
|
|
44
|
+
- mint pricing, reserves, and treasury effects still belong to the underlying 721 project rather than this resolver
|
|
19
45
|
|
|
20
46
|
## Journey 2: Dress A Banny And Put Accessories Into Resolver Custody
|
|
21
47
|
|
|
22
|
-
**
|
|
48
|
+
**Actor:** body owner.
|
|
49
|
+
|
|
50
|
+
**Intent:** equip a body with a background and outfits so the resolver serves the composed avatar.
|
|
23
51
|
|
|
24
|
-
**
|
|
52
|
+
**Preconditions**
|
|
53
|
+
- the caller controls the body and the accessories being equipped
|
|
54
|
+
- no active outfit lock blocks the change
|
|
55
|
+
- the selected pieces are compatible by category and collection rules
|
|
25
56
|
|
|
26
|
-
**Flow**
|
|
57
|
+
**Main Flow**
|
|
27
58
|
1. Call `decorateBannyWith(...)` for the target body.
|
|
28
|
-
2.
|
|
29
|
-
3.
|
|
59
|
+
2. The resolver checks compatibility and diffs old versus new attachments.
|
|
60
|
+
3. Equipped accessories move into resolver custody while attached.
|
|
61
|
+
4. The token URI for the body now reflects the combined SVG and metadata.
|
|
62
|
+
|
|
63
|
+
**Failure Modes**
|
|
64
|
+
- duplicate outfit categories or incompatible combinations are provided
|
|
65
|
+
- a transfer-back of previously attached items fails, leaving retained custody state that must be recovered later
|
|
66
|
+
- reviewers forget that the resolver, not the user wallet, holds equipped accessories while active
|
|
67
|
+
|
|
68
|
+
**Postconditions**
|
|
69
|
+
- the body renders with the newly attached composition
|
|
70
|
+
- attached accessories remain in resolver custody until replaced or cleared
|
|
30
71
|
|
|
31
72
|
## Journey 3: Lock A Banny's Appearance For A Period
|
|
32
73
|
|
|
33
|
-
**
|
|
74
|
+
**Actor:** body owner.
|
|
75
|
+
|
|
76
|
+
**Intent:** freeze the current appearance for the fixed lock window.
|
|
77
|
+
|
|
78
|
+
**Preconditions**
|
|
79
|
+
- the body already has a state worth freezing
|
|
80
|
+
- the caller understands the lock is intentionally fixed-duration
|
|
34
81
|
|
|
35
|
-
**
|
|
82
|
+
**Main Flow**
|
|
83
|
+
1. Call `lockOutfitChangesFor(...)`.
|
|
84
|
+
2. The resolver extends the lock for that body.
|
|
85
|
+
3. Future decoration or removal attempts must wait until the lock expires.
|
|
36
86
|
|
|
37
|
-
**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
87
|
+
**Failure Modes**
|
|
88
|
+
- a seller locks just before transfer and the buyer cannot re-style immediately
|
|
89
|
+
- integrations fail to surface lock state before listing or sale
|
|
90
|
+
|
|
91
|
+
**Postconditions**
|
|
92
|
+
- appearance changes are blocked until the lock expires
|
|
41
93
|
|
|
42
94
|
## Journey 4: Publish Or Repair On-Chain Art Assets
|
|
43
95
|
|
|
44
|
-
**
|
|
96
|
+
**Actor:** collection operator or art publisher.
|
|
97
|
+
|
|
98
|
+
**Intent:** make token URIs render complete onchain art.
|
|
99
|
+
|
|
100
|
+
**Preconditions**
|
|
101
|
+
- the relevant UPCs and content hashes are known
|
|
102
|
+
- the operator understands hashes are the commitment and SVG content must match them exactly
|
|
45
103
|
|
|
46
|
-
**
|
|
104
|
+
**Main Flow**
|
|
105
|
+
1. Register hashes with `setSvgHashesOf(...)`.
|
|
106
|
+
2. Upload matching payloads with `setSvgContentsOf(...)`.
|
|
107
|
+
3. Re-check token URI output after publication or repair.
|
|
47
108
|
|
|
48
|
-
**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
109
|
+
**Failure Modes**
|
|
110
|
+
- the uploaded SVG does not match the committed hash
|
|
111
|
+
- product names are missing or stale
|
|
112
|
+
- teams assume the 721 hook owns rendered output when this repo does
|
|
52
113
|
|
|
53
|
-
**
|
|
114
|
+
**Postconditions**
|
|
115
|
+
- token URIs can render the intended onchain art payloads for published UPCs
|
|
54
116
|
|
|
55
117
|
## Journey 5: Update Collection Metadata And Product Catalog Entries
|
|
56
118
|
|
|
57
|
-
**
|
|
119
|
+
**Actor:** collection operator.
|
|
58
120
|
|
|
59
|
-
**
|
|
121
|
+
**Intent:** change collection-level metadata and human-readable product labels.
|
|
60
122
|
|
|
61
|
-
**
|
|
123
|
+
**Preconditions**
|
|
124
|
+
- the operator has authority over the resolver metadata surface
|
|
125
|
+
|
|
126
|
+
**Main Flow**
|
|
62
127
|
1. Update collection metadata with `setMetadata(...)`.
|
|
63
|
-
2. Set or repair
|
|
64
|
-
3. Re-check token URI
|
|
128
|
+
2. Set or repair UPC names with `setProductNames(...)`.
|
|
129
|
+
3. Re-check a representative token URI so labels and art agree.
|
|
130
|
+
|
|
131
|
+
**Failure Modes**
|
|
132
|
+
- metadata and SVG state drift apart
|
|
133
|
+
- operators update catalog labels without checking already-minted assets
|
|
134
|
+
|
|
135
|
+
**Postconditions**
|
|
136
|
+
- collection-level metadata and UPC names line up with the currently published art set
|
|
65
137
|
|
|
66
138
|
## Journey 6: Unequip And Recover Custodied Accessories
|
|
67
139
|
|
|
68
|
-
**
|
|
140
|
+
**Actor:** body owner.
|
|
141
|
+
|
|
142
|
+
**Intent:** recover attached accessories from resolver custody.
|
|
143
|
+
|
|
144
|
+
**Preconditions**
|
|
145
|
+
- the current lock window, if any, has expired
|
|
146
|
+
- the owner understands old pieces may only be returned as part of a later decoration update
|
|
147
|
+
|
|
148
|
+
**Main Flow**
|
|
149
|
+
1. Replace or clear the equipped items through `decorateBannyWith(...)`.
|
|
150
|
+
2. The resolver attempts to return no-longer-equipped accessories.
|
|
151
|
+
3. Once returned, those NFTs can be transferred or re-used independently.
|
|
152
|
+
|
|
153
|
+
**Failure Modes**
|
|
154
|
+
- previously equipped pieces remain retained because transfer-back failed
|
|
155
|
+
- burned or otherwise unrecoverable pieces leave cosmetic phantom state until corrected
|
|
156
|
+
|
|
157
|
+
**Postconditions**
|
|
158
|
+
- no-longer-equipped accessories are either returned to the owner or remain explicitly retained pending recovery
|
|
69
159
|
|
|
70
|
-
|
|
160
|
+
## Trust Boundaries
|
|
71
161
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
3. The owner can now transfer, burn, or re-equip those pieces elsewhere.
|
|
162
|
+
- this repo is trusted for custody of equipped accessories while attached
|
|
163
|
+
- the underlying 721 hook remains the source of mint pricing, tier issuance, and treasury behavior
|
|
164
|
+
- metadata correctness depends on operators publishing the intended SVG hashes and contents
|
|
76
165
|
|
|
77
166
|
## Hand-Offs
|
|
78
167
|
|
package/foundry.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
2
|
+
"name": "@bannynet/core-v6",
|
|
3
|
+
"version": "0.0.23",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/mejango/banny-retail-v6"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20.0.0"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "forge test",
|
|
14
|
+
"coverage": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary",
|
|
15
|
+
"generate:migration": "node ./script/outfit_drop/generate-migration.js",
|
|
16
|
+
"deploy:mainnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks mainnets",
|
|
17
|
+
"deploy:testnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks testnets",
|
|
18
|
+
"deploy:testnets:drop:1": "source ./.env && npx sphinx propose ./script/Drop1.s.sol --networks testnets",
|
|
19
|
+
"deploy:mainnets:drop:1": "source ./.env && npx sphinx propose ./script/Drop1.s.sol --networks mainnets",
|
|
20
|
+
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'banny-core-v6'"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@bananapus/721-hook-v6": "^0.0.35",
|
|
24
|
+
"@bananapus/core-v6": "^0.0.34",
|
|
25
|
+
"@bananapus/permission-ids-v6": "^0.0.17",
|
|
26
|
+
"@bananapus/router-terminal-v6": "^0.0.26",
|
|
27
|
+
"@bananapus/suckers-v6": "^0.0.25",
|
|
28
|
+
"@croptop/core-v6": "^0.0.33",
|
|
29
|
+
"@openzeppelin/contracts": "^5.6.1",
|
|
30
|
+
"@rev-net/core-v6": "^0.0.32",
|
|
31
|
+
"keccak": "^3.0.4"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@bananapus/address-registry-v6": "^0.0.17",
|
|
35
|
+
"@sphinx-labs/plugins": "^0.33.3"
|
|
36
|
+
}
|
|
37
37
|
}
|
package/references/operations.md
CHANGED
|
@@ -21,5 +21,5 @@
|
|
|
21
21
|
|
|
22
22
|
## Useful Proof Points
|
|
23
23
|
|
|
24
|
-
- [`test/
|
|
25
|
-
- [`script/
|
|
24
|
+
- [`test/BannyAttacks.t.sol`](../test/BannyAttacks.t.sol) and [`test/TestAuditGaps.sol`](../test/TestAuditGaps.sol) for security-sensitive assumptions.
|
|
25
|
+
- [`script/Drop1.s.sol`](../script/Drop1.s.sol) and [`script/Add.Denver.s.sol`](../script/Add.Denver.s.sol) when a deployment issue is really a script/config problem.
|
package/references/runtime.md
CHANGED
|
@@ -24,4 +24,4 @@
|
|
|
24
24
|
- [`test/DecorateFlow.t.sol`](../test/DecorateFlow.t.sol) for the main equip/unequip lifecycle.
|
|
25
25
|
- [`test/OutfitTransferLifecycle.t.sol`](../test/OutfitTransferLifecycle.t.sol) for custody and return behavior.
|
|
26
26
|
- [`test/BannyAttacks.t.sol`](../test/BannyAttacks.t.sol) for adversarial flows.
|
|
27
|
-
- [`test/
|
|
27
|
+
- [`test/Fork.t.sol`](../test/Fork.t.sol), [`test/TestAuditGaps.sol`](../test/TestAuditGaps.sol), and [`test/TestQALastMile.t.sol`](../test/TestQALastMile.t.sol) for integration and pinned edge cases.
|
|
@@ -109,15 +109,10 @@ contract Banny721TokenUriResolver is
|
|
|
109
109
|
/// @custom:param upc The universal product code that the SVG hash represent.
|
|
110
110
|
mapping(uint256 upc => bytes32) public override svgHashOf;
|
|
111
111
|
|
|
112
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
113
112
|
string public override DEFAULT_ALIEN_EYES;
|
|
114
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
115
113
|
string public override DEFAULT_MOUTH;
|
|
116
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
117
114
|
string public override DEFAULT_NECKLACE;
|
|
118
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
119
115
|
string public override DEFAULT_STANDARD_EYES;
|
|
120
|
-
// forge-lint: disable-next-line(mixed-case-variable)
|
|
121
116
|
string public override BANNY_BODY;
|
|
122
117
|
|
|
123
118
|
//*********************************************************************//
|