Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
173 lines
6.3 KiB
Solidity
173 lines
6.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.4;
|
|
|
|
// Canonical ERC-6551 Registry — verbatim reference implementation from
|
|
// https://github.com/erc6551/reference (src/ERC6551Registry.sol). This is a
|
|
// FIXED REFERENCE CONTRACT, not a token: it deploys deterministic ERC-1167
|
|
// proxy accounts (via CREATE2) bound to (chainId, tokenContract, tokenId) and
|
|
// holds no state, mints nothing, and has no owner/admin. The public canonical
|
|
// deployment lives at 0x000000006551c19487814612e58FE06813775758 on chains
|
|
// that received the deterministic Nick-factory deploy; on AERE chain 2800 we
|
|
// deploy the identical source (the address differs because the deterministic
|
|
// factory salt is not replayed here — the bytecode/behaviour are identical).
|
|
|
|
interface IERC6551Registry {
|
|
/**
|
|
* @dev The registry MUST emit the ERC6551AccountCreated event upon successful account creation.
|
|
*/
|
|
event ERC6551AccountCreated(
|
|
address account,
|
|
address indexed implementation,
|
|
bytes32 salt,
|
|
uint256 chainId,
|
|
address indexed tokenContract,
|
|
uint256 indexed tokenId
|
|
);
|
|
|
|
/**
|
|
* @dev The registry MUST revert with AccountCreationFailed error if the create2 operation fails.
|
|
*/
|
|
error AccountCreationFailed();
|
|
|
|
/**
|
|
* @dev Creates a token bound account for a non-fungible token.
|
|
*
|
|
* If account has already been created, returns the account address without calling create2.
|
|
*
|
|
* Emits ERC6551AccountCreated event.
|
|
*
|
|
* @return account The address of the token bound account
|
|
*/
|
|
function createAccount(
|
|
address implementation,
|
|
bytes32 salt,
|
|
uint256 chainId,
|
|
address tokenContract,
|
|
uint256 tokenId
|
|
) external returns (address account);
|
|
|
|
/**
|
|
* @dev Returns the computed token bound account address for a non-fungible token.
|
|
*
|
|
* @return account The address of the token bound account
|
|
*/
|
|
function account(
|
|
address implementation,
|
|
bytes32 salt,
|
|
uint256 chainId,
|
|
address tokenContract,
|
|
uint256 tokenId
|
|
) external view returns (address account);
|
|
}
|
|
|
|
contract ERC6551Registry is IERC6551Registry {
|
|
function createAccount(
|
|
address implementation,
|
|
bytes32 salt,
|
|
uint256 chainId,
|
|
address tokenContract,
|
|
uint256 tokenId
|
|
) external returns (address) {
|
|
assembly {
|
|
// Memory Layout:
|
|
// ----
|
|
// 0x00 0xff (1 byte)
|
|
// 0x01 registry (address) (20 bytes)
|
|
// 0x15 salt (bytes32) (32 bytes)
|
|
// 0x35 Bytecode Hash (bytes32) (32 bytes)
|
|
// ----
|
|
// 0x55 ERC-1167 Constructor + Header (20 bytes)
|
|
// 0x69 implementation (address) (20 bytes)
|
|
// 0x5D ERC-1167 Footer (15 bytes)
|
|
// 0x8C salt (uint256) (32 bytes)
|
|
// 0xAC chainId (uint256) (32 bytes)
|
|
// 0xCC tokenContract (address) (32 bytes)
|
|
// 0xEC tokenId (uint256) (32 bytes)
|
|
|
|
// Silence unused variable warnings
|
|
pop(chainId)
|
|
|
|
// Copy bytecode + constant data to memory
|
|
calldatacopy(0x8c, 0x24, 0x80) // salt, chainId, tokenContract, tokenId
|
|
mstore(0x6c, 0x5af43d82803e903d91602b57fd5bf3) // ERC-1167 footer
|
|
mstore(0x5d, implementation) // implementation
|
|
mstore(0x49, 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73) // ERC-1167 constructor + header
|
|
|
|
// Copy create2 computation data to memory
|
|
mstore8(0x00, 0xff) // 0xFF
|
|
mstore(0x35, keccak256(0x55, 0xb7)) // keccak256(bytecode)
|
|
mstore(0x01, shl(96, address())) // registry address
|
|
mstore(0x15, salt) // salt
|
|
|
|
// Compute account address
|
|
let computed := keccak256(0x00, 0x55)
|
|
|
|
// If the account has not yet been deployed
|
|
if iszero(extcodesize(computed)) {
|
|
// Deploy account contract
|
|
let deployed := create2(0, 0x55, 0xb7, salt)
|
|
|
|
// Revert if the deployment fails
|
|
if iszero(deployed) {
|
|
mstore(0x00, 0x20188a59) // `AccountCreationFailed()`
|
|
revert(0x1c, 0x04)
|
|
}
|
|
|
|
// Store account address in memory before salt and chainId
|
|
mstore(0x6c, deployed)
|
|
|
|
// Emit the ERC6551AccountCreated event
|
|
log4(
|
|
0x6c,
|
|
0x60,
|
|
// `ERC6551AccountCreated(address,address,bytes32,uint256,address,uint256)`
|
|
0x79f19b3655ee38b1ce526556b7731a20c8f218fbda4a3990b6cc4172fdf88722,
|
|
implementation,
|
|
tokenContract,
|
|
tokenId
|
|
)
|
|
|
|
// Return the account address
|
|
return(0x6c, 0x20)
|
|
}
|
|
|
|
// Otherwise, return the computed account address
|
|
mstore(0x00, shr(96, shl(96, computed)))
|
|
return(0x00, 0x20)
|
|
}
|
|
}
|
|
|
|
function account(
|
|
address implementation,
|
|
bytes32 salt,
|
|
uint256 chainId,
|
|
address tokenContract,
|
|
uint256 tokenId
|
|
) external view returns (address) {
|
|
assembly {
|
|
// Silence unused variable warnings
|
|
pop(chainId)
|
|
pop(tokenContract)
|
|
pop(tokenId)
|
|
|
|
// Copy bytecode + constant data to memory
|
|
calldatacopy(0x8c, 0x24, 0x80) // salt, chainId, tokenContract, tokenId
|
|
mstore(0x6c, 0x5af43d82803e903d91602b57fd5bf3) // ERC-1167 footer
|
|
mstore(0x5d, implementation) // implementation
|
|
mstore(0x49, 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73) // ERC-1167 constructor + header
|
|
|
|
// Copy create2 computation data to memory
|
|
mstore8(0x00, 0xff) // 0xFF
|
|
mstore(0x35, keccak256(0x55, 0xb7)) // keccak256(bytecode)
|
|
mstore(0x01, shl(96, address())) // registry address
|
|
mstore(0x15, salt) // salt
|
|
|
|
// Store computed account address in memory
|
|
mstore(0x00, shr(96, shl(96, keccak256(0x00, 0x55))))
|
|
|
|
// Return computed account address
|
|
return(0x00, 0x20)
|
|
}
|
|
}
|
|
}
|