Skip to content

Commit 4791c59

Browse files
AztecBotspalladinosaleelPhilWindleLHerskind
authored
chore: Accumulated backports to v2 (#17814)
This PR accumulates backport commits throughout the day and will be auto-merged overnight. Latest backport: #17807 - fix: load masked values 🤖 This PR is managed automatically by the backport workflow. - #17785 - fix: Handle invalid ecdsa signatures - #17824 - chore: update zkpassport version to 0.10.0 - #17836 - chore: More mainnet config - #17738 - feat: coin issuer uses percentage of total supply - #17984 - chore: minor contract fixes --------- Co-authored-by: Santiago Palladino <[email protected]> Co-authored-by: saleel <[email protected]> Co-authored-by: PhilWindle <[email protected]> Co-authored-by: Phil Windle <[email protected]> Co-authored-by: LHerskind <[email protected]> Co-authored-by: Santiago Palladino <[email protected]>
1 parent 0dbfbe5 commit 4791c59

File tree

88 files changed

+2253
-783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2253
-783
lines changed

.github/workflows/deploy-fisherman-network.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ jobs:
123123
echo "USE_NETWORK_CONFIG=true" >> $GITHUB_ENV
124124
elif [[ "${{ inputs.l1_network }}" == "mainnet" ]]; then
125125
echo "NETWORK=mainnet" >> $GITHUB_ENV
126-
echo "NAMESPACE=ignition-fisherman-mainnet" >> $GITHUB_ENV
126+
echo "NAMESPACE=mainnet" >> $GITHUB_ENV
127127
echo "ETHEREUM_CHAIN_ID=1" >> $GITHUB_ENV
128128
echo "L1_NETWORK=mainnet" >> $GITHUB_ENV
129-
echo "SNAPSHOT_BUCKET_DIRECTORY=ignition-mainnet" >> $GITHUB_ENV
129+
echo "SNAPSHOT_BUCKET_DIRECTORY=mainnet" >> $GITHUB_ENV
130130
echo "USE_NETWORK_CONFIG=true" >> $GITHUB_ENV
131131
fi
132132

.test_patterns.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ tests:
7878
error_regex: "ultra_circuit_builder.test.cpp:631: Failure"
7979
owners:
8080
- *luke
81+
# http://ci.aztec-labs.com/1593f7c89e22b51b
82+
- regex: stdlib_primitives_tests stdlibBiggroupSecp256k1/1.WnafSecp256k1StaggerOutOfRangeFails
83+
error_regex: "biggroup_nafs: stagger fragment is not in range"
84+
owners:
85+
- *luke
8186

8287
# noir
8388
# Something to do with how I run the tests now. Think these are fine in nextest.

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
"merkleizing",
188188
"messagebox",
189189
"mimc",
190+
"mintable",
190191
"mktemp",
191192
"mload",
192193
"mockify",

l1-contracts/lib/circuits

Submodule circuits updated 410 files

l1-contracts/script/StakingAssetHandler.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ contract StakingAssetHandlerScript is Test {
3030
bytes32 public constant DEPOSIT_MERKLE_ROOT = bytes32(0);
3131

3232
ZKPassportVerifier internal constant zkPassportVerifier =
33-
ZKPassportVerifier(0xf7480fd0A9289c062C52532f11D31e0b7A30ABe3);
33+
ZKPassportVerifier(0x3101Bad9eA5fACadA5554844a1a88F7Fe48D4DE0);
3434

3535
TestERC20 public constant stakingAsset = TestERC20(0x6732CEDafCBF85Afa9B5C83f0385967840BBCe47);
3636
IRegistry public constant registry = IRegistry(0xc2F24280F5c7F4897370dFDEb30f79Ded14f1c81);

l1-contracts/src/core/interfaces/IRollup.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ struct RollupConfig {
8585
uint32 version;
8686
IERC20 feeAsset;
8787
IFeeJuicePortal feeAssetPortal;
88-
IRewardDistributor rewardDistributor;
8988
IVerifier epochProofVerifier;
9089
IInbox inbox;
9190
IOutbox outbox;

l1-contracts/src/core/libraries/rollup/BlobLib.sol

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {Vm} from "forge-std/Vm.sol";
2222
* The VM_ADDRESS (0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) is a special address used to detect
2323
* when the contract is running in a Foundry test environment. This address is derived from
2424
* keccak256("hevm cheat code") and corresponds to Foundry's VM contract that provides testing utilities.
25-
* When VM_ADDRESS.code.length > 0, it indicates we're in a test environment, allowing the library to:
25+
* When block.chainid == 31337 && VM_ADDRESS.code.length > 0, it indicates we're in a test environment,
26+
* allowing the library to:
2627
* - Use Foundry's getBlobBaseFee() cheatcode instead of block.blobbasefee
2728
* - Use Foundry's getBlobhashes() cheatcode instead of the blobhash() opcode
2829
* This enables comprehensive testing of blob functionality without requiring actual blob transactions.
@@ -47,7 +48,7 @@ library BlobLib {
4748
* @return uint256 - The blob base fee
4849
*/
4950
function getBlobBaseFee() internal view returns (uint256) {
50-
if (VM_ADDRESS.code.length > 0) {
51+
if (block.chainid == 31_337 && VM_ADDRESS.code.length > 0) {
5152
return Vm(VM_ADDRESS).getBlobBaseFee();
5253
}
5354
return block.blobbasefee;
@@ -62,7 +63,7 @@ library BlobLib {
6263
* @return blobHash - The blob hash
6364
*/
6465
function getBlobHash(uint256 _index) internal view returns (bytes32 blobHash) {
65-
if (VM_ADDRESS.code.length > 0) {
66+
if (block.chainid == 31_337 && VM_ADDRESS.code.length > 0) {
6667
// We know that this one is ABHORRENT. But it should not exists, and only will
6768
// be hit in testing.
6869
bytes32[] memory blobHashes = Vm(VM_ADDRESS).getBlobhashes();

l1-contracts/src/core/messagebridge/Inbox.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ contract Inbox is IInbox {
114114

115115
bytes16 updatedRollingHash = bytes16(keccak256(abi.encodePacked(rollingHash, leaf)));
116116
state = InboxState({
117-
rollingHash: bytes16(updatedRollingHash),
117+
rollingHash: updatedRollingHash,
118118
totalMessagesInserted: totalMessagesInserted + 1,
119119
inProgress: inProgress
120120
});

l1-contracts/src/core/reward-boost/RewardBooster.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ contract RewardBooster is IBooster {
115115
}
116116

117117
function _toShares(uint256 _value) internal view returns (uint256) {
118-
if (_value > CONFIG_MAX_SCORE) {
118+
if (_value >= CONFIG_MAX_SCORE) {
119119
return CONFIG_K;
120120
}
121121
uint256 t = (CONFIG_MAX_SCORE - _value);

l1-contracts/src/governance/CoinIssuer.sol

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,44 +11,120 @@ import {Ownable2Step} from "@oz/access/Ownable2Step.sol";
1111
/**
1212
* @title CoinIssuer
1313
* @author Aztec Labs
14-
* @notice A contract that allows minting of coins at a maximum fixed rate
14+
* @notice A contract that allows minting of coins at a maximum percentage rate per year using discrete annual budgets
15+
*
16+
* This contract uses a discrete annual budget model:
17+
* - Years are fixed periods from deployment:
18+
* - year 0 = [deployment, deployment + 365d)
19+
* - year 1 = [deployment + 365d, deployment + (2) * 365d)
20+
* - ...
21+
* - year n = [deployment + 365d * n, deployment + (n + 1) * 365d)
22+
* - Each year's budget is calculated at the start of that year based on the actual supply at that moment
23+
* - Budget = totalSupply() × NOMINAL_ANNUAL_PERCENTAGE_CAP / 1e18
24+
* - Unused budget from year N is LOST when year N+1 begins (use-it-or-lose-it)
25+
*
26+
* Rate semantics: If the full budget is minted every year, the effective annual inflation rate equals
27+
* NOMINAL_ANNUAL_PERCENTAGE_CAP. For example, setting the rate to 0.10e18 (10%) and fully minting each
28+
* year will result in supply growing by exactly 10% annually: supply(year N) = supply(year 0) × (1.10)^N
29+
*
30+
* Partial minting: If less than the full budget is minted in year N, the remaining allowance is lost
31+
* at the year N→N+1 boundary. Year N+1's budget is calculated based on the actual supply at the start
32+
* of year N+1, which reflects only what was actually minted.
33+
*
34+
* @dev The NOMINAL_ANNUAL_PERCENTAGE_CAP is in e18 precision where 1e18 = 100%
35+
*
36+
* @dev The token MUST have a non-zero initial supply at deployment, or an alternative way to mint the token.
1537
*/
1638
contract CoinIssuer is ICoinIssuer, Ownable {
1739
IMintableERC20 public immutable ASSET;
18-
uint256 public immutable RATE;
19-
uint256 public timeOfLastMint;
40+
uint256 public immutable NOMINAL_ANNUAL_PERCENTAGE_CAP;
41+
uint256 public immutable DEPLOYMENT_TIME;
2042

21-
constructor(IMintableERC20 _asset, uint256 _rate, address _owner) Ownable(_owner) {
43+
// Note that the state variables below are "cached":
44+
// they are only updated when minting after a year boundary.
45+
uint256 public cachedBudgetYear;
46+
uint256 public cachedBudget;
47+
48+
constructor(IMintableERC20 _asset, uint256 _annualPercentage, address _owner) Ownable(_owner) {
2249
ASSET = _asset;
23-
RATE = _rate;
24-
timeOfLastMint = block.timestamp;
50+
NOMINAL_ANNUAL_PERCENTAGE_CAP = _annualPercentage;
51+
DEPLOYMENT_TIME = block.timestamp;
52+
53+
cachedBudgetYear = 0;
54+
cachedBudget = _getNewBudget();
55+
56+
emit BudgetReset(0, cachedBudget);
2557
}
2658

2759
function acceptTokenOwnership() external override(ICoinIssuer) onlyOwner {
2860
Ownable2Step(address(ASSET)).acceptOwnership();
2961
}
3062

3163
/**
32-
* @notice Mint tokens up to the `mintAvailable` limit
33-
* Beware that the mintAvailable will be reset to 0, and not just
34-
* reduced by the amount minted.
64+
* @notice Mint `_amount` tokens to `_to`
65+
*
66+
* @dev The `_amount` must be within the `cachedBudget`
3567
*
3668
* @param _to - The address to receive the funds
3769
* @param _amount - The amount to mint
3870
*/
3971
function mint(address _to, uint256 _amount) external override(ICoinIssuer) onlyOwner {
40-
uint256 maxMint = mintAvailable();
41-
require(_amount <= maxMint, Errors.CoinIssuer__InsufficientMintAvailable(maxMint, _amount));
42-
timeOfLastMint = block.timestamp;
72+
// Update state if we've crossed into a new year (will reset budget and forfeit unused amount)
73+
_updateBudgetIfNeeded();
74+
75+
require(_amount <= cachedBudget, Errors.CoinIssuer__InsufficientMintAvailable(cachedBudget, _amount));
76+
cachedBudget -= _amount;
77+
4378
ASSET.mint(_to, _amount);
4479
}
4580

4681
/**
47-
* @notice The amount of funds that is available for "minting"
82+
* @notice The amount of funds that is available for "minting" in the current year
83+
* If we've crossed into a new year since the last mint, returns the fresh budget
84+
* for the new year based on current supply.
4885
*
4986
* @return The amount mintable
5087
*/
5188
function mintAvailable() public view override(ICoinIssuer) returns (uint256) {
52-
return RATE * (block.timestamp - timeOfLastMint);
89+
uint256 currentYear = _yearSinceGenesis();
90+
91+
// Until the budget is stale, return the cached budget
92+
if (cachedBudgetYear >= currentYear) {
93+
return cachedBudget;
94+
}
95+
96+
// Crossed into new year(s): compute fresh budget
97+
return _getNewBudget();
98+
}
99+
100+
/**
101+
* @notice Internal function to update year and budget when crossing year boundaries
102+
*
103+
* @dev If multiple years have passed without minting, jumps directly to current year
104+
* and all intermediate years' budgets are lost
105+
*/
106+
function _updateBudgetIfNeeded() private {
107+
uint256 currentYear = _yearSinceGenesis();
108+
// If the budget is for the past, update the budget.
109+
if (cachedBudgetYear < currentYear) {
110+
cachedBudgetYear = currentYear;
111+
cachedBudget = _getNewBudget();
112+
113+
emit BudgetReset(currentYear, cachedBudget);
114+
}
115+
}
116+
117+
/**
118+
* @notice Internal function to compute the current year since genesis
119+
*/
120+
function _yearSinceGenesis() private view returns (uint256) {
121+
return (block.timestamp - DEPLOYMENT_TIME) / 365 days;
122+
}
123+
124+
/**
125+
* @notice Internal function to compute a fresh budget
126+
*/
127+
function _getNewBudget() private view returns (uint256) {
128+
return ASSET.totalSupply() * NOMINAL_ANNUAL_PERCENTAGE_CAP / 1e18;
53129
}
54130
}

0 commit comments

Comments
 (0)