Skip to content

Docs/b20 reference - #1775

Open
soheimam wants to merge 1 commit into
masterfrom
docs/b20-reference
Open

Docs/b20 reference#1775
soheimam wants to merge 1 commit into
masterfrom
docs/b20-reference

Conversation

@soheimam

@soheimam soheimam commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What changed? Why?

Added b20 reference using b20 spec

@mintlify

mintlify Bot commented Aug 5, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
base 🟢 Ready View Preview Aug 5, 2026, 7:22 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@cb-heimdall

Copy link
Copy Markdown
Collaborator

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

@roethke roethke left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following mirror comments left on #1766.

  • Systematic selector/topic bug: enum params are hashed by type name instead of uint8, so every enum-bearing selector/topic is wrong.
  • SEIZE_RECEIVER_POLICY missing: the standard has 6 policy scopes; the reference shows 5, which also makes seizeWithMemo wrong (it gates the recipient).
  • Plus seizeWithMemo return type, finalizeUpdateAdmin access-control, ChildPoliciesOutsideOfRange signature, the burnBlocked "no longer part of this interface" claim, and missing MIN/MAX_COMPOSITE_CHILD_POLICIES + UIMultiplierUpdated.


| Field | Value |
|---|---|
| Selector | `0xb263cb84` |

@roethke roethke Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the selector is incorrect. The enum type name was hashed instead of uint8. ABI selectors normalize enums to uint8, so this should be createB20(uint8,bytes32,bytes,bytes[])0x62975e6a (verified with cast). This is systematic across every enum-bearing signature; also wrong: getB20Address0x8c30260f, and the createPolicy* functions. The Canonical signature fields should show uint8 too.


| Event | Topic0 | Summary |
|---|---|---|
| `B20Created` | `0x86ee7a93da43b07286ea4c925a31ba17c41eb00c5ea396883bf32abfe5e73cfc` | Emitted once per `createB20` invocation, after the token's identity is sealed |

@roethke roethke Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both enum-derived values in these tables are wrong (same root cause: enum name instead of uint8):

  • B20Created topic0 should be 0xfd9bf2730513a1709722ff379a0844dfd8f997d600693c2bcc659e188bbdba0d (B20Created(address,uint8,string,string,uint8,bytes)).
  • UnsupportedVersion selector should be 0xc0d8b4e0 (UnsupportedVersion(uint8,uint8)).


| Field | Value |
|---|---|
| Selector | `0xe494a1f6` |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same enum-selector bug: computed from createPolicy(address,PolicyType). Correct ABI signature is createPolicy(address,uint8)0xca5d55f6 (verified with cast). Related: createPolicyWithAccounts0xa2d3044f, createCompositePolicy0x6fdd1491.

## Signature

```solidity
function seizeWithMemo(address from, address to, uint256 amount, bytes32 memo) external returns (bool);

@roethke roethke Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues vs IB20.sol:474:

  1. Return type: source is ... external; with no return value; returns (bool) (and "always true on success") is incorrect.

function seizeWithMemo(address from, address to, uint256 amount, bytes32 memo) external;

  1. Policy semantics (stale): source gates the recipient under SEIZE_RECEIVER_POLICY and reverts PolicyForbids(SEIZE_RECEIVER_POLICY, …) when to isn't authorized (IB20.sol:460–467); this page says to is not policy-checked. Documents an older version of the interface.


## Access control

Callable by the policy admin for the target policy.

@roethke roethke Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access control is inverted. Per IPolicyRegistry.sol:161–168, this must be called by the staged pending admin (reverts Unauthorized otherwise), it "promotes the caller to active admin." The current policy admin cannot call it; that's the point of the two-step transfer.

| [`DEFAULT_ADMIN_ROLE`](/base-chain/specs/upgrades/beryl/b20/specification/reference/interfaces/IB20/DEFAULT_ADMIN_ROLE) | `0xa217fddf` | The default top-level admin role (`bytes32(0)`). Required to call `grantRole`, `revokeRole`, |
| [`MINT_ROLE`](/base-chain/specs/upgrades/beryl/b20/specification/reference/interfaces/IB20/MINT_ROLE) | `0xe9a9c850` | Required to call `mint` and `mintWithMemo`. |
| [`BURN_ROLE`](/base-chain/specs/upgrades/beryl/b20/specification/reference/interfaces/IB20/BURN_ROLE) | `0xb930908f` | Required to call `burn` and `burnWithMemo`. |
| [`BURN_BLOCKED_ROLE`](/base-chain/specs/upgrades/beryl/b20/specification/reference/interfaces/IB20/BURN_BLOCKED_ROLE) | `0x32ad9be8` | Required to call the deprecated `burnBlocked` (no longer part of this interface; retained for |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

burnBlocked is still declared in IB20.sol:453 (marked DEPRECATED), so "no longer part of this interface" is inaccurate. Also: burnBlocked(address,uint256) has no reference page (the only non-constant IB20 function without one), and SEIZE_RECEIVER_POLICY() (IB20.sol:274) is missing from this function table.

---


## Functions

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two functions from IPolicyRegistry.sol are missing from this index (and have no pages): MIN_COMPOSITE_CHILD_POLICIES() (:242) and MAX_COMPOSITE_CHILD_POLICIES() (:247). 16 in source, 14 documented — and these are what the composite-range prose references.

| error | `LengthMismatch` | `0xab8b67c6` | `IB20Asset` | A batched function was called with parallel arrays of differing lengths. |
| event | `Memo` | `0x6989f5818dcfd11f8cd53b27c94cec33dae1589735f03e639cba54553a1825e8` | `IB20` | Emitted by `transferWithMemo`, `transferFromWithMemo`, `mintWithMemo`, and `burnWithMemo` |
| error | `MissingRequiredField` | `0x4a43ae87` | `IB20Factory` | A required string argument was the empty string. |
| event | `MultiplierUpdateCancelled` | `0xf8929975f3e67bbd1e5ec70d4cceaa7cce7ea0e811720f29c96cf1724de09397` | `IB20Asset` | A scheduled multiplier update was cancelled. Emitted by `cancelScheduledMultiplier`, |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UIMultiplierUpdated(uint256,uint256,uint256) is missing from this index. It's declared in IScaledUIAmount.sol (inherited by IB20Asset) and is the primary event emitted on multiplier changes — MultiplierUpdateCancelled is listed, but the update event itself is not.

| Transfer receiver | `keccak256("TRANSFER_RECEIVER_POLICY")` |
| Transfer executor | `keccak256("TRANSFER_EXECUTOR_POLICY")` |
| Mint receiver | `keccak256("MINT_RECEIVER_POLICY")` |
| Seize holder | `keccak256("SEIZE_HOLDER_POLICY")` |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the 6th policy scope: SEIZE_RECEIVER_POLICY (keccak256("SEIZE_RECEIVER_POLICY")) is defined in B20Constants.sol but absent from this table, which claims to list the B20Constants.sol values.

| `TRANSFER_RECEIVER_POLICY` | `to` | `transfer`, `transferFrom`, and memo variants |
| `TRANSFER_EXECUTOR_POLICY` | `msg.sender` | `transferFrom` when `msg.sender != from` |
| `MINT_RECEIVER_POLICY` | `to` | `mint`, `mintWithMemo` |
| `SEIZE_HOLDER_POLICY` | `from` | `seizeWithMemo`; holder is seizable only when not authorized |

@roethke roethke Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Policy Integration table is missing SEIZE_RECEIVER_POLICY (6th scope), and the Seize section (~line 118) says seizeWithMemo only requires from to be denied by SEIZE_HOLDER_POLICY, it omits that to is gated by SEIZE_RECEIVER_POLICY (IB20.sol:460–467).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants