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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ACCOUNT_ADDRESS=
ADDRESS=
PRIVATE_KEY=
ETHERSCAN_API_KEY=

Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ lib/

# Coverage reports
lcov.info

# Slither reports
mutation_campaign/
mutation.results
2 changes: 1 addition & 1 deletion CAST_COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ For Radius Testnet, you can use the `--gas-price 0` flag to avoid needing enough
## Check ETH Balance

```sh
cast balance $ADDRESS --rpc-url radius-testnet
cast balance $ADDRESS --rpc-url $RPC
```

## EVMAuth View Functions (Read-Only)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,15 @@ Choose [ERC-6909] when you:
- Prefer a simpler token transfer model
- Want to extend the contract with custom features

Both versions of EVMAuth are fairly large. EVMAuth1155 is right near the limit, while EVMAuth6909 has a bit more headroom for exapnsion.
Both versions of EVMAuth are fairly large. EVMAuth1155 is right near the limit, while EVMAuth6909 has a bit more headroom for expansion.

```text
╭------------------------------+------------------+-------------------+--------------------+---------------------╮
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
+================================================================================================================+
| EVMAuth1155 | 24,555 | 24,614 | 21 | 24,538 |
| EVMAuth1155 | 24,516 | 24,575 | 60 | 24,577 |
|------------------------------+------------------+-------------------+--------------------+---------------------|
| EVMAuth6909 | 22,424 | 22,483 | 2,152 | 26,669 |
| EVMAuth6909 | 22,247 | 22,306 | 2,329 | 26,846 |
╰------------------------------+------------------+-------------------+--------------------+---------------------╯
```

Expand Down
81 changes: 45 additions & 36 deletions script/ExampleDeploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,69 @@ pragma solidity ^0.8.24;
import { EVMAuth } from "src/base/EVMAuth.sol";
import { BaseDeploy1155, BaseDeploy6909 } from "script/BaseDeploy.s.sol";

abstract contract Deploy {
uint48 public initialDelay = 2 days; // 48-hour admin transfer delay
address public initialDefaultAdmin = address(0);
address payable public initialTreasury = payable(address(0));
address public upgradeManager = address(0);
address public accessManager = address(0);
address public tokenManager = address(0);
address public minter = address(0);
address public burner = address(0);
address public treasurer = address(0);

function setUp() public virtual {
if (initialDefaultAdmin == address(0)) initialDefaultAdmin = msg.sender;
if (initialTreasury == payable(address(0))) initialTreasury = payable(msg.sender);
if (upgradeManager == address(0)) upgradeManager = msg.sender;
if (accessManager == address(0)) accessManager = msg.sender;
if (tokenManager == address(0)) tokenManager = msg.sender;
if (minter == address(0)) minter = msg.sender;
if (burner == address(0)) burner = msg.sender;
if (treasurer == address(0)) treasurer = msg.sender;
}
}

/**
* @dev Example deployment script for EVMAuth1155
* @dev Deployment script for EVMAuth1155
*/
contract ExampleDeploy1155 is BaseDeploy1155 {
contract Deploy1155 is BaseDeploy1155, Deploy {
/**
* @dev Main deployment function. Sets initializer parameters, then executes the deployment.
*/
function run() public {
uint48 initialDelay = 2 days; // 48-hour admin transfer delay
address initialDefaultAdmin = msg.sender; // Deployer as initial admin
address payable initialTreasury = payable(msg.sender); // Deployer address as initial treasury
setUp();

// Grant all roles to the deployer
EVMAuth.RoleGrant[] memory roleGrants = new EVMAuth.RoleGrant[](6);
roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, msg.sender);
roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, msg.sender);
roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, msg.sender);
roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, msg.sender);
roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, msg.sender);
roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, msg.sender);

// Example token URI with {id} placeholder, per ERC-1155 metadata standard
string memory uri = "https://token-cdn-domain/{id}.json";

// Execute the deployment
deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, uri);
roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, upgradeManager);
roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, accessManager);
roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, tokenManager);
roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, minter);
roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, burner);
roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, treasurer);

deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, "");
}
}

/**
* @dev Example deployment script for EVMAuth6909
* @dev Deployment script for EVMAuth6909
*/
contract ExampleDeploy6909 is BaseDeploy6909 {
contract Deploy6909 is BaseDeploy6909, Deploy {
/**
* @dev Main deployment function. Sets initializer parameters, then executes the deployment.
*/
function run() public {
uint48 initialDelay = 2 days; // 48-hour admin transfer delay
address initialDefaultAdmin = msg.sender; // Deployer as initial admin
address payable initialTreasury = payable(msg.sender); // Deployer address as initial treasury
setUp();

// Grant all roles to the deployer
EVMAuth.RoleGrant[] memory roleGrants = new EVMAuth.RoleGrant[](6);
roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, msg.sender);
roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, msg.sender);
roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, msg.sender);
roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, msg.sender);
roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, msg.sender);
roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, msg.sender);

// Example contract URI, per EIP-6909 content URI extension
string memory uri = "https://token-cdn-domain/contract-metadata.json";

// Execute the deployment
deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, uri);
roleGrants[0] = EVMAuth.RoleGrant(UPGRADE_MANAGER_ROLE, upgradeManager);
roleGrants[1] = EVMAuth.RoleGrant(ACCESS_MANAGER_ROLE, accessManager);
roleGrants[2] = EVMAuth.RoleGrant(TOKEN_MANAGER_ROLE, tokenManager);
roleGrants[3] = EVMAuth.RoleGrant(MINTER_ROLE, minter);
roleGrants[4] = EVMAuth.RoleGrant(BURNER_ROLE, burner);
roleGrants[5] = EVMAuth.RoleGrant(TREASURER_ROLE, treasurer);

deploy(initialDelay, initialDefaultAdmin, initialTreasury, roleGrants, "");
}
}
49 changes: 25 additions & 24 deletions src/EVMAuth1155.abi
Original file line number Diff line number Diff line change
Expand Up @@ -555,30 +555,6 @@
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "isAcceptedERC20PaymentToken",
"inputs": [
{
"name": "id",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "paymentToken",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "isApprovedForAll",
Expand Down Expand Up @@ -1520,6 +1496,31 @@
],
"anonymous": false
},
{
"type": "event",
"name": "ExpiredTokensPruned",
"inputs": [
{
"name": "from",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "id",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Initialized",
Expand Down
2 changes: 1 addition & 1 deletion src/EVMAuth1155.bin

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/EVMAuth1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ contract EVMAuth1155 is ERC1155URIStorageUpgradeable, EVMAuth {
_setURI(id, tokenURI);
}

/// @inheritdoc TokenEphemeral
function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual override {
uint256[] memory ids = new uint256[](1);
uint256[] memory values = new uint256[](1);
ids[0] = id;
values[0] = amount;
super._update(account, address(0), ids, values);
}

/// @inheritdoc TokenPurchasable
function _mintPurchasedTokens(address to, uint256 id, uint256 amount) internal virtual override {
_mint(to, id, amount, "");
Expand Down
49 changes: 25 additions & 24 deletions src/EVMAuth6909.abi
Original file line number Diff line number Diff line change
Expand Up @@ -598,30 +598,6 @@
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "isAcceptedERC20PaymentToken",
"inputs": [
{
"name": "id",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "paymentToken",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "isFrozen",
Expand Down Expand Up @@ -1668,6 +1644,31 @@
],
"anonymous": false
},
{
"type": "event",
"name": "ExpiredTokensPruned",
"inputs": [
{
"name": "from",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "id",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Initialized",
Expand Down
2 changes: 1 addition & 1 deletion src/EVMAuth6909.bin

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/EVMAuth6909.sol
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ contract EVMAuth6909 is ERC6909MetadataUpgradeable, ERC6909ContentURIUpgradeable
_setDecimals(id, decimals);
}

/// @inheritdoc TokenEphemeral
function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual override {
super._update(account, address(0), id, amount);
}

/// @inheritdoc TokenPurchasable
function _mintPurchasedTokens(address to, uint256 id, uint256 amount) internal virtual override {
_mint(to, id, amount);
Expand Down
41 changes: 8 additions & 33 deletions src/base/EVMAuth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ abstract contract EVMAuth is
function _createToken(EVMAuthTokenConfig calldata config) internal virtual returns (uint256 id) {
id = _claimNextTokenID();

_setPrice(id, config.price);
_setERC20Prices(id, config.erc20Prices);
_setTTL(id, config.ttl);
_setTransferable(id, config.transferable);
TokenPurchasable._setPrice(id, config.price);
TokenPurchasable._setERC20Prices(id, config.erc20Prices);
TokenEphemeral._setTTL(id, config.ttl);
TokenTransferable._setTransferable(id, config.transferable);

emit EVMAuthTokenConfigured(id, config);

Expand All @@ -240,39 +240,14 @@ abstract contract EVMAuth is
* @custom:emits EVMAuthTokenConfigured
*/
function _updateToken(uint256 id, EVMAuthTokenConfig calldata config) internal virtual tokenExists(id) {
_setPrice(id, config.price);
_setERC20Prices(id, config.erc20Prices);
_setTTL(id, config.ttl);
_setTransferable(id, config.transferable);
TokenPurchasable._setPrice(id, config.price);
TokenPurchasable._setERC20Prices(id, config.erc20Prices);
TokenEphemeral._setTTL(id, config.ttl);
TokenTransferable._setTransferable(id, config.transferable);

emit EVMAuthTokenConfigured(id, config);
}

/// @inheritdoc TokenPurchasable
function _setPrice(uint256 id, uint256 price) internal virtual override tokenExists(id) {
TokenPurchasable._setPrice(id, price);
}

/// @inheritdoc TokenPurchasable
function _setERC20Price(uint256 id, address token, uint256 price) internal virtual override tokenExists(id) {
TokenPurchasable._setERC20Price(id, token, price);
}

/// @inheritdoc TokenPurchasable
function _setERC20Prices(uint256 id, PaymentToken[] calldata prices) internal virtual override tokenExists(id) {
TokenPurchasable._setERC20Prices(id, prices);
}

/// @inheritdoc TokenEphemeral
function _setTTL(uint256 id, uint256 ttl) internal virtual override tokenExists(id) {
TokenEphemeral._setTTL(id, ttl);
}

/// @inheritdoc TokenTransferable
function _setTransferable(uint256 id, bool transferable) internal virtual override tokenExists(id) {
super._setTransferable(id, transferable);
}

/// @inheritdoc UUPSUpgradeable
function _authorizeUpgrade(address newImplementation) internal virtual override onlyRole(UPGRADE_MANAGER_ROLE) {
// This will revert if the caller is not authorized.
Expand Down
2 changes: 1 addition & 1 deletion src/base/TokenAccessControl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/P
* @title TokenAccessControl
* @author EVMAuth
* @notice Provides comprehensive role-based access control for token management.
* @dev Abstract contract implementing six distinct roles for granular permission control:.
* @dev Abstract contract implementing six distinct roles for granular permission control:
* upgrade management, access management, token management, minting, burning, and treasury operations.
* Includes account freezing via AccountFreezable and contract pausing via PausableUpgradeable.
*/
Expand Down
Loading