Implement init maxSupply when deploying TST

This commit is contained in:
stubbsta 2025-09-16 10:32:37 +02:00
parent c3ec4be6b4
commit a6bee099a2
No known key found for this signature in database
3 changed files with 62 additions and 13 deletions

View File

@ -11,13 +11,29 @@ contract DeployTokenWithProxy is BaseScript {
}
function deploy() public returns (ERC1967Proxy) {
// Read desired max supply from env or use default
uint256 defaultMaxSupply = vm.envOr({ name: "MAX_SUPPLY", defaultValue: uint256(1_000_000 * 10 ** 18) });
// Validate value is sensible
require(defaultMaxSupply > 0, "MAX_SUPPLY must be > 0");
// Deploy the initial implementation
address implementation = address(new TestStableToken());
// Encode the initialize call
bytes memory data = abi.encodeCall(TestStableToken.initialize, (1_000_000 * 10 ** 18));
// Encode the initialize call (maxSupply)
bytes memory initData = abi.encodeCall(TestStableToken.initialize, (defaultMaxSupply));
// Deploy the proxy with initialization data
return new ERC1967Proxy(implementation, data);
ERC1967Proxy proxy = new ERC1967Proxy(implementation, initData);
// Post-deploy assertions to ensure initialization succeeded
// These revert the script if validation fails.
address proxyAddr = address(proxy);
// Check maxSupply set
uint256 actualMax = TestStableToken(proxyAddr).maxSupply();
if (actualMax != defaultMaxSupply) revert("Proxy maxSupply mismatch after initialization");
return proxy;
}
}

View File

@ -21,10 +21,12 @@ token distribution while mimicking DAI's behaviour.
## Usage
Add environment variable `MAX_SUPPLY` to set the maximum supply of the token, otherwise it defaults to 10 million tokens.
### Deploy new TestStableToken with proxy contract
This script deploys both the proxy and the TestStableToken implementation, initializing the proxy to point to the new
implementation.
This script deploys both the proxy contract and the TestStableToken implementation contract, initializing the proxy to
point to the new implementation.
```bash
ETH_FROM=$DEPLOYER_ACCOUNT_ADDRESS forge script script/DeployTokenWithProxy.s.sol:DeployTokenWithProxy --rpc-url $RPC_URL --broadcast --private_key $DEPLOYER_ACCOUNT_PRIVATE_KEY
@ -36,22 +38,32 @@ or
MNEMONIC=$TWELVE_WORD_MNEMONIC forge script script/DeployTokenWithProxy.s.sol:DeployTokenWithProxy --rpc-url $RPC_URL --broadcast
```
### Deploy only TestStableToken contract implementation
### Deploy only TestStableToken implementation contract
This script deploys only the TestStableToken implementation, which can then be used to update the proxy contract to
point to this new implementation.
This script deploys only the TestStableToken implementation. The proxy contract can then be updated to point to this new
implementation.
```bash
forge script test/TestStableToken.sol:TestStableTokenFactory --tc TestStableTokenFactory --rpc-url $RPC_URL --private-key $DEPLOYER_ACCOUNT_PRIVATE_KEY --broadcast
ETH_FROM=$DEPLOYER_ACCOUNT_ADDRESS forge script test/TestStableToken.sol:TestStableTokenFactory --tc TestStableTokenFactory --rpc-url $RPC_URL --private-key $DEPLOYER_ACCOUNT_PRIVATE_KEY --broadcast
```
### Update the proxy contract to point to the new implementation
### Update the proxy contract to point to the new implementation (safe, recommended)
When upgrading a UUPS/ERC1967 proxy you should perform the upgrade and initialization in the same transaction to avoid
leaving the proxy in an uninitialized state. Use `upgradeToAndCall(address,bytes)` with the initializer calldata.
```bash
# Upgrade the proxy to a new implementation
cast send $TOKEN_PROXY_ADDRESS "upgradeTo(address)" $NEW_IMPLEMENTATION_ADDRESS --rpc-url $RPC_URL --private-key $DEPLOYER_ACCOUNT_PRIVATE_KEY
# Encode the initializer calldata (example: set MAX_SUPPLY to 1_000_000 * 10**18)
DATA=$(cast abi-encode "initialize(uint256)" 1000000000000000000000000)
# Perform upgrade and call initializer atomically
cast send $TOKEN_PROXY_ADDRESS "upgradeToAndCall(address,bytes)" $NEW_IMPLEMENTATION_ADDRESS $DATA --rpc-url $RPC_URL --private-key $DEPLOYER_ACCOUNT_PRIVATE_KEY
```
If you must call `upgradeTo` separately (not recommended), follow up immediately with an `initialize(...)` call in the
same transaction or as the next transaction from the owner/multisig. However, prefer `upgradeToAndCall` to eliminate the
time window where the proxy points to a new implementation but its storage (e.g., `maxSupply`) is uninitialized.
### Add account to the allowlist to enable minting
```bash

View File

@ -8,6 +8,7 @@ import { ERC20PermitUpgradeable } from
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
error AccountNotMinter();
error AccountAlreadyMinter();
@ -90,7 +91,27 @@ contract TestStableToken is
}
contract TestStableTokenFactory is BaseScript {
/// @notice Deploys the implementation and an ERC1967 proxy, initializing the proxy atomically.
/// @dev Reads `MAX_SUPPLY` from environment (wei). Defaults to 1_000_000 * 10**18.
function run() public broadcast returns (address) {
return address(new TestStableToken());
// Read desired max supply from env or use default
uint256 defaultMaxSupply = vm.envOr({ name: "MAX_SUPPLY", defaultValue: uint256(1_000_000 * 10 ** 18) });
// Validate value is sensible
if (defaultMaxSupply == 0) revert("MAX_SUPPLY must be > 0");
// Deploy the implementation
address implementation = address(new TestStableToken());
// Encode initializer calldata to run in proxy context (maxSupply)
bytes memory initData = abi.encodeCall(TestStableToken.initialize, (defaultMaxSupply));
// Deploy ERC1967Proxy with initialization data so storage (owner, maxSupply) is set atomically
ERC1967Proxy proxy = new ERC1967Proxy(implementation, initData);
// // Only check maxSupply was initialized; owner checks are optional for basic deployments
// address proxyAddr = address(proxy);
return address(proxy);
}
}