Skip to content
Closed
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
87 changes: 87 additions & 0 deletions packages/cli/abis/DotnsRootGateway.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
[
{
"type": "constructor",
"inputs": [
{
"name": "registry",
"type": "address"
}
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "execute",
"inputs": [
{
"name": "targets",
"type": "address[]"
},
{
"name": "payloads",
"type": "bytes[]"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "protocolRegistry",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view"
},
{
"type": "event",
"name": "RootCallForwarded",
"inputs": [
{
"name": "target",
"type": "address",
"indexed": true
},
{
"name": "selector",
"type": "bytes4",
"indexed": true
}
],
"anonymous": false
},
{
"type": "error",
"name": "NotRoot",
"inputs": []
},
{
"type": "error",
"name": "TargetNotProtocol",
"inputs": [
{
"name": "target",
"type": "address"
}
]
},
{
"type": "error",
"name": "LengthMismatch",
"inputs": []
},
{
"type": "error",
"name": "EmptyBatch",
"inputs": []
},
{
"type": "error",
"name": "InvalidRegistry",
"inputs": []
}
]
11 changes: 7 additions & 4 deletions packages/cli/src/cli/commands/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,16 +548,19 @@ async function executeGovernanceRegistration(
// than silently widening what a grant holder can mint here.
validateGovernanceLabel(label);

// registerReserved is gated on the name whitelist (or Root), not on the
// caller's PoP tier. Surfaced as information only: a Root-origin mint skips
// the grant check, so a `false` here is a warning rather than a hard stop.
// registerReserved is gated on the name whitelist (or a call from the
// DotnsRootGateway), not on the caller's PoP tier. Surfaced as information
// only: a gateway-routed governance mint skips the grant check, so a
// `false` here is a warning rather than a hard stop.
const granted = await step("Checking name grant", async () =>
isNameGrantedTo(session.ctx, label, session.caller).catch(() => null),
);
if (granted === false) {
console.log(
chalk.yellow(" ⚠ name is not granted to the caller; ") +
chalk.gray("registerReserved reverts with NameNotGranted unless the origin is Root"),
chalk.gray(
"registerReserved reverts with NameNotGranted unless called through the DotnsRootGateway",
),
);
} else if (granted === true) {
console.log(chalk.gray(" granted: ") + chalk.green("yes"));
Expand Down
45 changes: 43 additions & 2 deletions packages/cli/src/commands/accountChecks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ export async function checkAccountMapped(
// uses to locate the name whitelist (`DotnsConstants.NAME_WHITELIST`).
const NAME_WHITELIST_KEY = "0x6e616d6557686974656c69737400000000000000000000000000000000000000";

// `bytes32("rootGateway")`: the ProtocolRegistry key for `DotnsRootGateway`, the
// contract governance calls must now be routed through (dotns
// fix/root-origin-gates, checked against the branch's finalized tip: the ABI,
// this key, and the gateway-address authorisation model below all match).
// Nothing in this SDK constructs a governance dispatch today, so nothing
// resolves this yet; it is exported so a future governance-dispatch helper
// does not have to duplicate this lookup. Prefer this over hardcoding an
// address: the gateway still has no CREATE3 book entry in either address
// book below, so a hardcoded address would need updating the moment it
// deploys anyway.
const ROOT_GATEWAY_KEY = "0x726f6f7447617465776179000000000000000000000000000000000000000000";

const PROTOCOL_REGISTRY_GET_ABI = [
{
type: "function",
Expand Down Expand Up @@ -61,6 +73,34 @@ export async function resolveNameWhitelist(ctx: DotnsContext): Promise<Address>
return whitelist;
}

// Resolves DotnsRootGateway from the protocol registry, the same way
// resolveNameWhitelist resolves the whitelist. Governance calls to the 16
// gated entry points across the name whitelist, PopRules, the PoP controller,
// and the governance branch of registerReserved (grantName, setReserved,
// reserveLiteName, and so on) must now be dispatched as
// `DotnsRootGateway.execute(targets, payloads)`, with the gateway itself as
// the direct Root callee: it is the only contract that reads Root origin
// directly (via `callerIsRoot`, non-proxied so the check survives), and every
// gated contract downstream instead authorises on
// `msg.sender == protocolRegistry.get(ROOT_GATEWAY)`. Unused today: nothing
// in this SDK builds a Root dispatch.
export async function resolveRootGateway(ctx: DotnsContext): Promise<Address> {
const registry = await read<Address>(
ctx,
ctx.contracts.DOTNS_REGISTRAR_CONTROLLER,
DOTNS_REGISTRAR_CONTROLLER_ABI,
"protocolRegistry",
[],
);
const gateway = await read<Address>(ctx, registry, PROTOCOL_REGISTRY_GET_ABI, "get", [
ROOT_GATEWAY_KEY,
]);
if (gateway === "0x0000000000000000000000000000000000000000") {
throw new Error("No DotnsRootGateway is configured on this network's protocol registry.");
}
return gateway;
}

// Grant record of `label` on the name whitelist: status, the beneficiary a
// grant names, and whether the claim window is open.
export async function getNameGrant(ctx: DotnsContext, name: string): Promise<NameGrantResult> {
Expand All @@ -79,8 +119,9 @@ export async function getNameGrant(ctx: DotnsContext, name: string): Promise<Nam
};
}

// Whether `registerReserved` would accept `label` for `owner` without Root:
// the controller requires `isGrantedTo(label, owner)` on the name whitelist.
// Whether `registerReserved` would accept `label` for `owner` without a call
// through the DotnsRootGateway: the controller requires `isGrantedTo(label,
// owner)` on the name whitelist.
export async function isNameGrantedTo(
ctx: DotnsContext,
name: string,
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import LabelStore from "../../abis/LabelStore.json" with { type: "json" };
import UserStore from "../../abis/UserStore.json" with { type: "json" };
import DotnsPopController from "../../abis/DotnsPopController.json" with { type: "json" };
import DotnsNameWhitelist from "../../abis/DotnsNameWhitelist.json" with { type: "json" };
// Forwards governance calls to the 16 gated entry points listed in the dotns
// fix/root-origin-gates change; see resolveRootGateway in accountChecks.ts.
// Vendored ahead of the SDK actually dispatching through it.
import DotnsRootGateway from "../../abis/DotnsRootGateway.json" with { type: "json" };

const DEFAULT_DOTLI_GATEWAYS = ["dot.li", "paseo.li"] as const;

Expand Down Expand Up @@ -100,6 +104,7 @@ export const LABEL_STORE_ABI = LabelStore.abi as Abi;
export const USER_STORE_ABI = UserStore.abi as Abi;
export const DOTNS_POP_CONTROLLER_ABI = DotnsPopController as Abi;
export const DOTNS_NAME_WHITELIST_ABI = DotnsNameWhitelist as Abi;
export const DOTNS_ROOT_GATEWAY_ABI = DotnsRootGateway as Abi;
export const PERSONHOOD_ABI = [
{
type: "function",
Expand Down
Loading