-
Notifications
You must be signed in to change notification settings - Fork 3
wip on proxy agnostic #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughRemoved the legacy deployment script; introduced V2 config shapes and deployer contracts (beacon-set and clone deployers); refactored ReceiptVault to use ReceiptVaultConfigV2 and direct receipt addresses; migrated vaults, tests, and fixtures to new deployer-based flows and normalized import paths. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Test as Test / Caller
participant Deployer as Deployer (BeaconSet / CloneDeployer)
participant Cloner as Clones / BeaconFactory
participant ReceiptImpl as Receipt impl
participant VaultImpl as Vault impl
participant ReceiptProxy as Receipt Proxy
participant VaultProxy as Vault Proxy
Note over Test,Deployer: Beacon-set deploy flow (OffchainAsset)
Test->>Deployer: newOffchainAssetReceiptVault(configV2)
Deployer->>Cloner: deploy Receipt beacon (initialReceiptImpl)
Deployer->>Cloner: deploy Vault beacon (initialVaultImpl)
Deployer->>ReceiptProxy: deploy BeaconProxy(receiptBeacon)
ReceiptProxy->>ReceiptImpl: delegatecall initialize(vaultAddr)
Deployer->>VaultProxy: deploy BeaconProxy(vaultBeacon)
VaultProxy->>VaultImpl: delegatecall initialize(configV2 with receipt)
Deployer->>Test: emit Deployment(sender, vault, receipt) / return vault
Note over Test,Deployer: Clone-deployer flow (ERC20PriceOracle)
Test->>Deployer: newERC20PriceOracleReceiptVault(configV2)
Deployer->>Cloner: clone Receipt implementation
Deployer->>ReceiptImpl: call initialize(vaultPlaceholder)
Deployer->>Cloner: clone Vault implementation
Deployer->>VaultImpl: call initialize(configV2 with receipt)
Deployer->>Test: emit CloneDeployerDeployment(sender, vault, receipt) / return vault
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45–60 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🔇 Additional comments (5)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol (1)
55-64: Fix incorrect field access pattern.The code accesses
config.receiptVaultConfig.vaultConfig.*, butReceiptVaultConfigV2does not have a nestedvaultConfigfield. The struct has flat fields:asset,name,symbol, andreceipt.Apply this diff to fix the field access:
- assertEq(keccak256(bytes(vault.name())), keccak256(bytes(config.receiptVaultConfig.vaultConfig.name))); - assertEq(config.receiptVaultConfig.vaultConfig.name, shareName); + assertEq(keccak256(bytes(vault.name())), keccak256(bytes(config.receiptVaultConfig.name))); + assertEq(config.receiptVaultConfig.name, shareName); - assertEq(keccak256(bytes(vault.symbol())), keccak256(bytes(config.receiptVaultConfig.vaultConfig.symbol))); - assertEq(config.receiptVaultConfig.vaultConfig.symbol, shareSymbol); + assertEq(keccak256(bytes(vault.symbol())), keccak256(bytes(config.receiptVaultConfig.symbol))); + assertEq(config.receiptVaultConfig.symbol, shareSymbol); - assertEq(address(config.receiptVaultConfig.vaultConfig.asset), address(I_ASSET)); + assertEq(address(config.receiptVaultConfig.asset), address(I_ASSET));test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol (1)
44-118: Fix incorrect struct field access in event assertionsLines 99, 102, 105 access a non-existent
vaultConfignested field.ReceiptVaultConfigV2hasasset,name, andsymbolas direct fields:
- Line 99: Change
config.receiptVaultConfig.vaultConfig.nametoconfig.receiptVaultConfig.name- Line 102: Change
config.receiptVaultConfig.vaultConfig.symboltoconfig.receiptVaultConfig.symbol- Line 105: Change
config.receiptVaultConfig.vaultConfig.assettoconfig.receiptVaultConfig.assetLine 108 (
config.receiptVaultConfig.receipt) is correct.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
script/Deploy.sol(1 hunks)src/abstract/ReceiptVault.sol(2 hunks)src/concrete/vault/ERC20PriceOracleReceiptVault.sol(4 hunks)src/concrete/vault/OffchainAssetReceiptVault.sol(4 hunks)test/abstract/ERC20PriceOracleReceiptVaultTest.sol(2 hunks)test/concrete/ConcreteReceiptVault.sol(2 hunks)test/lib/LibERC20PriceOracleReceiptVaultCreator.sol(2 hunks)test/lib/LibOffchainAssetVaultCreator.sol(2 hunks)test/src/abstract/ReceiptVault.decimals.t.sol(2 hunks)test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol(3 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol(3 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol(4 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rainix CI
test/abstract/ERC20PriceOracleReceiptVaultTest.sol
[error] 59-59: Solidity compiler error: Member "ERC20PriceOracleReceiptVaultInitialized" not found or not visible after argument-dependent lookup. Command failed: forge build.
test/lib/LibERC20PriceOracleReceiptVaultCreator.sol
[error] 25-25: Solidity compiler error: Wrong argument count for struct constructor: 3 arguments given but expected 4. Command failed: forge build.
🔇 Additional comments (17)
src/abstract/ReceiptVault.sol (2)
55-66: LGTM! Struct definition is clear.The refactoring from
VaultConfigtoReceiptVaultConfigV2with the addition of thereceiptfield is well-structured. The comments accurately describe each field.
158-170: LGTM! Initialization logic correctly updated.The function signature and initialization logic properly use the new
ReceiptVaultConfigV2structure. The receipt validation at Line 166 ensures the receipt's manager matches the vault address.test/concrete/ConcreteReceiptVault.sol (1)
8-8: LGTM! Test updated to use new config type.The import and abi.decode statements correctly reference
ReceiptVaultConfigV2, aligning with the struct rename.Also applies to: 21-21
test/lib/LibOffchainAssetVaultCreator.sol (1)
7-8: LGTM! Helper correctly updated to V2 config types.The imports and configuration construction properly use
OffchainAssetReceiptVaultConfigV2with the nestedreceiptVaultConfigfield containingReceiptVaultConfigV2.Also applies to: 25-28
test/src/abstract/ReceiptVault.decimals.t.sol (1)
7-7: LGTM! Test correctly uses new config type.The import and abi.encode statement properly reference
ReceiptVaultConfigV2.Also applies to: 26-26
script/Deploy.sol (1)
8-10: LGTM! Imports updated to V2 config types.The imports correctly reference the renamed configuration structs:
ERC20PriceOracleReceiptVaultConfigV2andReceiptVaultConfigV2.test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol (1)
7-7: LGTM! Config type correctly updated.The import, variable declaration, and abi.decode statement properly use
ERC20PriceOracleReceiptVaultConfigV2.Also applies to: 33-33, 44-44
test/abstract/ERC20PriceOracleReceiptVaultTest.sol (1)
11-11: LGTM! Config type correctly updated.The import and abi.decode statements properly use
ERC20PriceOracleReceiptVaultConfigV2, and the field access correctly referencesconfig.receiptVaultConfig.receipt.Also applies to: 61-63
test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol (3)
19-23: Imports updated correctly.The import changes align with the renamed config types.
411-418: Config construction is consistent within this file.The
OffchainAssetReceiptVaultConfigV2construction matches the pattern used intestMintSimpleRealReceiptVault.
86-95: No action required. TheReceiptVaultConfigV2struct is correctly defined with direct fields (asset,name,symbol,receipt) insrc/abstract/ReceiptVault.sol, and the code at lines 88-91 correctly instantiates it with direct field initialization:ReceiptVaultConfigV2({asset: address(0), name: "Test Vault", symbol: "TVLT"}). This usage is consistent across the entire codebase. There is no nestedvaultConfigfield inReceiptVaultConfigV2.src/concrete/vault/OffchainAssetReceiptVault.sol (3)
5-12: Import changes align with the config type consolidation.The import of
ReceiptVaultConfigV2replaces the previousVaultConfigandReceiptVaultConfigtypes.
46-49: Struct definition is well-structured.The
OffchainAssetReceiptVaultConfigV2struct cleanly nests theReceiptVaultConfigV2configuration.
304-331: Initialization logic correctly updated for new config structure.The
initializefunction properly:
- Decodes the config as
OffchainAssetReceiptVaultConfigV2- Passes
config.receiptVaultConfigto the base initialization- Validates asset address against
config.receiptVaultConfig.asset- Emits the event with the correct config structure
src/concrete/vault/ERC20PriceOracleReceiptVault.sol (3)
5-11: Import changes are consistent with the refactor.The import of
ReceiptVaultConfigV2aligns with the broader config type consolidation.
24-28: Struct definition follows the established pattern.
ERC20PriceOracleReceiptVaultConfigV2correctly usesReceiptVaultConfigV2for the nested config field.
83-127: Event and initialization correctly migrated to V2.The event signature, decoding, and initialization flow are properly updated to use the V2 config types. The pattern is consistent with
OffchainAssetReceiptVault.sol.
test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
test/abstract/ERC20PriceOracleReceiptVaultTest.sol (1)
17-32: Incomplete migration:I_DEPLOYERis referenced but not defined.The
createVaultfunction at line 44 callsI_DEPLOYER.newERC20PriceOracleReceiptVault(...), butI_DEPLOYERis never declared or initialized in this contract. The constructor still uses the old factory-based pattern withI_FACTORY.Additionally,
ReceiptVaultConfigV2is used at line 47 but not imported.Apply a fix similar to
OffchainAssetReceiptVaultTest.sol:
- Add import for the beacon deployer and
ReceiptVaultConfigV2- Declare
I_DEPLOYERas an immutable- Initialize it in the constructor with an
ERC20PriceOracleReceiptVaultBeaconSetDeployer(or equivalent)Alternatively, if the beacon deployer for ERC20PriceOracleReceiptVault doesn't exist yet, revert to the factory-based pattern until it's implemented:
function createVault(IPriceOracleV2 priceOracle, string memory name, string memory symbol) internal returns (ERC20PriceOracleReceiptVault) { - return I_DEPLOYER.newERC20PriceOracleReceiptVault( - ERC20PriceOracleReceiptVaultConfigV2({ - initialAdmin: address(this), - receiptVaultConfig: ReceiptVaultConfigV2({ - asset: address(I_ASSET), - name: name, - symbol: symbol, - receipt: address(0) - }), - vaultPriceOracle: priceOracle - }) - ); + // TODO: Migrate to beacon deployer when available + return ERC20PriceOracleReceiptVault( + I_FACTORY.clone( + address(I_IMPLEMENTATION), + abi.encode( + ERC20PriceOracleReceiptVaultConfigV2({ + priceOracle: priceOracle, + receiptVaultConfig: ReceiptVaultConfigV2({ + asset: address(I_ASSET), + name: name, + symbol: symbol, + receipt: address(I_RECEIPT_IMPLEMENTATION) + }) + }) + ) + ) + ); }test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol (1)
66-66: Incorrect field name:config.priceOracleshould beconfig.vaultPriceOracle.Based on the V2 config structure shown in
ERC20PriceOracleReceiptVaultTest.solline 53, the field is namedvaultPriceOracle, notpriceOracle.- assertEq(address(config.priceOracle), address(vaultPriceOracle)); + assertEq(address(config.vaultPriceOracle), address(vaultPriceOracle));test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol (1)
47-115: Remove theviewkeyword fromnewOffchainAssetReceiptVaultand add a return statement.The function at
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol:28-48is marked asviewbut performs state-modifying operations (creates new BeaconProxy contracts and callsinitialize()). Additionally, the function declares a return typeOffchainAssetReceiptVaultbut lacks a return statement. Change the function signature to removeviewand addreturn offchainAssetReceiptVault;before the closing brace.
♻️ Duplicate comments (2)
test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol (1)
36-48: Event signature mismatch: test looks for old event.The test checks for the old event signature
"ERC20PriceOracleReceiptVaultInitialized(address,(address,(address,(address,string,string))))"but the contract now emitsERC20PriceOracleReceiptVaultInitializedV2with a different struct layout (ERC20PriceOracleReceiptVaultConfigV2).Update the event signature to match the V2 event:
for (uint256 i = 0; i < logs.length; i++) { if ( logs[i].topics[0] - == keccak256( - "ERC20PriceOracleReceiptVaultInitialized(address,(address,(address,(address,string,string))))" - ) + == ERC20PriceOracleReceiptVault.ERC20PriceOracleReceiptVaultInitializedV2.selector ) {test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol (1)
11-12: Duplicate import should be removed.Line 12 contains a duplicate import of
OffchainAssetReceiptVaultConfigV2, which is already imported on line 11.Apply this diff to remove the duplicate:
import { OffchainAssetReceiptVault, OffchainAssetReceiptVaultConfigV2, - OffchainAssetReceiptVaultConfigV2, ZeroInitialAdmin, NonZeroAsset } from "src/concrete/vault/OffchainAssetReceiptVault.sol";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (14)
script/Deploy.sol(0 hunks)src/abstract/ReceiptVault.sol(3 hunks)src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)src/concrete/vault/ERC20PriceOracleReceiptVault.sol(4 hunks)src/concrete/vault/OffchainAssetReceiptVault.sol(4 hunks)test/abstract/ERC20PriceOracleReceiptVaultTest.sol(3 hunks)test/abstract/OffchainAssetReceiptVaultTest.sol(1 hunks)test/concrete/ConcreteReceiptVault.sol(1 hunks)test/lib/LibERC20PriceOracleReceiptVaultCreator.sol(0 hunks)test/lib/LibOffchainAssetVaultCreator.sol(0 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol(4 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol(4 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.mint.t.sol(1 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol(0 hunks)
💤 Files with no reviewable changes (4)
- script/Deploy.sol
- test/lib/LibOffchainAssetVaultCreator.sol
- test/lib/LibERC20PriceOracleReceiptVaultCreator.sol
- test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
🔇 Additional comments (13)
test/src/concrete/vault/OffchainAssetReceiptVault.mint.t.sol (1)
144-144: LGTM!The vault creation now uses the simplified
createVaulthelper method from the base test class, which aligns with the migration to the beacon-based deployment pattern.test/abstract/OffchainAssetReceiptVaultTest.sol (2)
27-38: LGTM!The constructor correctly initializes the beacon-based deployer with proper implementations and ownership configuration. This aligns with the migration from factory-based to beacon-based deployment.
40-55: LGTM!The
createVaulthelper correctly uses the newOffchainAssetReceiptVaultConfigV2structure with:
asset: address(0)- correct for offchain assetsreceipt: address(0)- signals the deployer to create a new receiptThis properly delegates vault creation to the beacon-based deployer.
test/concrete/ConcreteReceiptVault.sol (1)
15-20: LGTM!The test contract correctly migrates to
ReceiptVaultConfigV2for initialization, properly decoding and passing the config to the base__ReceiptVault_initfunction.test/abstract/ERC20PriceOracleReceiptVaultTest.sol (1)
66-70: Event selector and config type updated correctly.The event selector has been updated to
ERC20PriceOracleReceiptVaultInitializedV2and the config decoding now usesERC20PriceOracleReceiptVaultConfigV2, which aligns with the V2 migration.However, this code will not compile until the
I_DEPLOYERissue increateVaultis resolved.src/concrete/vault/OffchainAssetReceiptVault.sol (2)
46-49: LGTM!The
OffchainAssetReceiptVaultConfigV2struct correctly nestsReceiptVaultConfigV2, aligning with the broader config consolidation in this PR.
302-329: LGTM!The initialization logic correctly:
- Decodes the V2 config structure
- Passes
config.receiptVaultConfigto the base initializer- Validates that asset is zero (required for offchain vaults)
- Emits the V2 event with the proper config structure
test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol (1)
34-44: LGTM! Config structure correctly uses the V2 pattern.The nested config structure properly uses
ReceiptVaultConfigV2withinOffchainAssetReceiptVaultConfigV2, and the field namereceiptVaultConfigis correct.src/abstract/ReceiptVault.sol (3)
55-66: LGTM! Config struct consolidation simplifies the initialization interface.The new
ReceiptVaultConfigV2struct cleanly consolidates configuration and includes thereceiptfield, replacing the previous two-struct approach. This aligns with the proxy-agnostic refactoring objectives.
132-134: Constructor correctly simplified for proxy-agnostic deployment.Removing factory and receipt implementation parameters from the constructor is consistent with the new pattern where the receipt is pre-created and passed during initialization rather than cloned.
147-159: The deployment sequence already guarantees receipt manager is set before vault initialization.The
OffchainAssetReceiptVaultBeaconSetDeployerexplicitly controls initialization order: it callsreceipt.initialize(vault_address)(which sets the manager) before callingvault.initialize(). When__ReceiptVault_initexecutes, the receipt's manager is already correctly configured, so theWrongManagervalidation will pass by design. This is not a concern requiring external verification.src/concrete/vault/ERC20PriceOracleReceiptVault.sol (2)
6-28: LGTM! Config struct updated consistently to V2 pattern.The changes correctly adopt
ReceiptVaultConfigV2and nest it withinERC20PriceOracleReceiptVaultConfigV2. Field naming and structure align with the refactoring objectives.
104-125: LGTM! Initialization flow correctly updated for V2 config.The decoding, parent initialization call, and event emission all correctly use the V2 config structure. Line 111 properly passes
config.receiptVaultConfigto__ReceiptVault_init.
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol
Outdated
Show resolved
Hide resolved
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol (1)
37-47: Update the event signature to match the V2 event.The hardcoded
keccak256hash uses the old event signature without the V2 suffix and missing thereceiptfield in the struct. This will cause the test to fail when searching for the event log.Apply this diff to use the correct event selector:
for (uint256 i = 0; i < logs.length; i++) { if ( logs[i].topics[0] - == keccak256( - "ERC20PriceOracleReceiptVaultInitialized(address,(address,(address,(address,string,string))))" - ) + == ERC20PriceOracleReceiptVault.ERC20PriceOracleReceiptVaultInitializedV2.selector ) {Alternatively, use the correct V2 event signature with the receipt field:
for (uint256 i = 0; i < logs.length; i++) { if ( logs[i].topics[0] == keccak256( - "ERC20PriceOracleReceiptVaultInitialized(address,(address,(address,(address,string,string))))" + "ERC20PriceOracleReceiptVaultInitializedV2(address,(address,(address,string,string,address)))" ) ) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol(1 hunks)test/abstract/ERC20PriceOracleReceiptVaultTest.sol(3 hunks)test/abstract/OwnerFreezableOwnerFreezeUntilTest.sol(1 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol(3 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
🔇 Additional comments (7)
test/abstract/ERC20PriceOracleReceiptVaultTest.sol (4)
11-12: LGTM!The import updates correctly introduce the V2 configuration types and the new clone deployer, aligning with the refactored vault creation approach.
Also applies to: 17-20
27-27: LGTM!The deployer initialization is correctly structured, with appropriate implementation addresses provided to the deployer configuration.
Also applies to: 31-31, 34-39
52-63: LGTM!The vault creation logic correctly uses the new deployer-based approach with
ERC20PriceOracleReceiptVaultConfigV2. Settingreceipt: address(0)is appropriate since the deployer creates and assigns the receipt contract.
74-74: LGTM!The event handling correctly uses
ERC20PriceOracleReceiptVaultInitializedV2.selectorand decodes toERC20PriceOracleReceiptVaultConfigV2, with proper nested field access for the receipt address. This resolves the issue previously flagged in past reviews.Also applies to: 76-78
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol (1)
21-24: LGTM!The constructor correctly initializes the immutable implementation addresses from the provided configuration.
test/src/concrete/vault/ERC20PriceOracleReceiptVault.construct.t.sol (2)
7-7: LGTM!The import and configuration type correctly updated to use
ERC20PriceOracleReceiptVaultConfigV2.Also applies to: 33-33
44-44: LGTM!The event decoding, field access, and assertions correctly reflect the V2 configuration structure. The
msgSenderassertion toaddress(0)is appropriate for the initialization context.Also applies to: 52-52, 55-61
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
test/abstract/OffchainAssetReceiptVaultTest.sol (1)
55-71: Missing assertion when event is not found.Unlike
ERC20PriceOracleReceiptVaultTest.getReceipt()which assertseventFound, this function silently returnsaddress(0)when the event isn't found. This could mask test failures.} // Return an receipt contract + require(eventFound, "OffchainAssetReceiptVaultInitializedV2 event log not found"); return ReceiptContract(receiptAddress); }
♻️ Duplicate comments (2)
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
30-30: Consider using a custom error for gas efficiency and consistency.The codebase uses custom errors elsewhere (e.g.,
ZeroInitialAdmin,NonZeroAsset). For consistency:+error NonZeroReceiptAddress(); + contract OffchainAssetReceiptVaultBeaconSetDeployer { // ... - require(config.receiptVaultConfig.receipt == address(0), "Receipt address must be zero"); + if (config.receiptVaultConfig.receipt != address(0)) { + revert NonZeroReceiptAddress(); + }src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol (1)
27-49: LGTM!The previously flagged issues (incorrect
viewmodifier and missing return statement) have been addressed. The deployment flow is correct: clone receipt → clone vault → initialize receipt with vault reference → set receipt in config → initialize vault → return vault.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (13)
src/abstract/ReceiptVault.sol(4 hunks)src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol(1 hunks)src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)src/concrete/vault/ERC20PriceOracleReceiptVault.sol(4 hunks)src/concrete/vault/OffchainAssetReceiptVault.sol(4 hunks)test/abstract/ERC20PriceOracleReceiptVaultTest.sol(3 hunks)test/abstract/OffchainAssetReceiptVaultAuthorizerV1Test.sol(2 hunks)test/abstract/OffchainAssetReceiptVaultTest.sol(1 hunks)test/concrete/ConcreteReceiptVault.sol(1 hunks)test/src/abstract/ReceiptVault.decimals.t.sol(2 hunks)test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol(2 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.ierc165.t.sol(1 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
🔇 Additional comments (20)
test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol (1)
21-26: Clean simplification of test setup.The constructor now uses the
createVaulthelper, which removes the boilerplate factory and implementation setup. This aligns well with the broader refactor to beacon/deployer-based vault creation.test/abstract/OffchainAssetReceiptVaultAuthorizerV1Test.sol (1)
5-5: LGTM!The inheritance change to
OffchainAssetReceiptVaultTestprovides access to thecreateVaulthelper and other test utilities, aligning with the broader test refactor pattern.Also applies to: 15-15
test/src/concrete/vault/OffchainAssetReceiptVault.ierc165.t.sol (1)
12-27: LGTM!Using the no-argument constructor to instantiate the implementation directly is appropriate for interface support testing. The
supportsInterfacemethod works on the implementation contract, and this approach correctly validates that all expected interfaces (IERC165, IReceiptManagerV2, IReceiptVaultV3, ICloneableV2, IAuthorizeV1) are supported.test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol (2)
61-61: LGTM!The
createVaulthelper simplifies the test setup while maintaining the same test functionality.
377-377: LGTM!Consistent use of the
createVaulthelper across tests.test/concrete/ConcreteReceiptVault.sol (1)
5-13: LGTM - Clean migration to ReceiptVaultConfigV2.The contract correctly migrates from
VaultConfigtoReceiptVaultConfigV2for initialization. The simplified structure aligns with the PR's goal of making vaults proxy-agnostic by including the receipt address directly in the config rather than cloning it. The struct contains all necessary fields (asset, name, symbol, receipt) and the initialization flow is correct.test/src/abstract/ReceiptVault.decimals.t.sol (1)
20-46: LGTM! Clone-based deployment pattern is correctly implemented.The test properly demonstrates the new clone-based initialization:
- Receipt is initialized with the vault address
- Vault is initialized with
ReceiptVaultConfigV2containing the receipt address- The circular reference between receipt and vault is established correctly
The fuzz test with
assetDecimalsvalidates decimal pass-through from the underlying asset.test/abstract/OffchainAssetReceiptVaultTest.sol (1)
25-36: LGTM! Beacon-based deployer integration is correct.The constructor properly initializes the beacon set deployer with the receipt and vault implementations. The deployer will manage beacon proxy creation for both contracts.
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
1-48: LGTM! Previous review issues have been addressed.The deployer correctly:
- Uses
IBeacontypes for beacon references (addressing past review)- Removes
viewmodifier (addressing past review)- Returns the created vault (addressing past review)
- Properly initializes receipt before vault, establishing the manager relationship
test/abstract/ERC20PriceOracleReceiptVaultTest.sol (2)
26-37: LGTM! Clone deployer integration is correct.The constructor properly initializes the clone deployer with receipt and vault implementation addresses.
62-83: LGTM! Event handling is properly implemented.The
getReceiptfunction correctly:
- Uses the V2 event selector (addressing past review)
- Decodes the V2 config struct
- Asserts that the event was found before returning
src/abstract/ReceiptVault.sol (3)
46-57: LGTM! Consolidated config struct simplifies initialization.
ReceiptVaultConfigV2combines all required fields includingreceipt, enabling the deployer pattern where receipt is created externally and passed in.
123-125: LGTM! Parameterless constructor enables proxy patterns.Disabling initializers in the constructor is the correct pattern for contracts intended to be used as implementations behind proxies (clones, beacon proxies, etc.).
138-150: LGTM! Critical manager validation ensures correct initialization.The check at lines 146-149 verifies that the receipt contract was initialized with this vault as its manager. This prevents misconfigured deployments where the receipt and vault are not properly linked.
src/concrete/vault/OffchainAssetReceiptVault.sol (3)
5-11: LGTM!Import changes correctly bring in
ReceiptVaultConfigV2andICLONEABLE_V2_SUCCESSfor the V2 config migration.
45-48: LGTM!The struct field type update to
ReceiptVaultConfigV2aligns with the V2 config migration across the codebase.
301-328: LGTM!The initialization logic correctly migrates to V2 config:
- Decodes
OffchainAssetReceiptVaultConfigV2- Passes
config.receiptVaultConfigto__ReceiptVault_init- Validates asset at the correct nested path
- Event emission with the V2 config type
src/concrete/vault/ERC20PriceOracleReceiptVault.sol (3)
5-5: LGTM!Import correctly updated to use
ReceiptVaultConfigV2for the V2 config migration.
18-22: LGTM!The struct is correctly updated with V2 naming and uses
ReceiptVaultConfigV2for the nested config.
98-119: LGTM!The initialization logic correctly migrates to V2 config:
- Decodes
ERC20PriceOracleReceiptVaultConfigV2- Passes
config.receiptVaultConfigto__ReceiptVault_init- Emits the renamed V2 event with proper config type
test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol (1)
11-12: Duplicate import still present.
OffchainAssetReceiptVaultConfigV2is imported twice on consecutive lines (lines 11 and 12). This was already flagged in a previous review.Apply this diff to remove the duplicate:
import { OffchainAssetReceiptVault, OffchainAssetReceiptVaultConfigV2, - OffchainAssetReceiptVaultConfigV2, ZeroInitialAdmin, NonZeroAsset } from "src/concrete/vault/OffchainAssetReceiptVault.sol";src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
26-41: Use custom error for non‑zero receipt and document ACL on deployer
- Line 30: For gas and consistency with the rest of the codebase, prefer a custom error over a string require, e.g.:
error NonZeroReceiptAddress(); function newOffchainAssetReceiptVault(OffchainAssetReceiptVaultConfigV2 memory config) external returns (OffchainAssetReceiptVault) { if (config.receiptVaultConfig.receipt != address(0)) { revert NonZeroReceiptAddress(); } // ... }
- The function is permissionless (
externalwith no modifier). If that’s not intentional, add the appropriate access control (e.g.,onlyOwner) or at least document in NatSpec that anyone can deploy new off‑chain asset vaults via this contract.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol(3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
🔇 Additional comments (5)
test/src/concrete/vault/OffchainAssetReceiptVault.construct.t.sol (4)
22-43: Well-structured zero admin validation test.The manual beacon proxy setup and nested config structure correctly test that
initialAdmincannot beaddress(0). The test appropriately creates the receipt first and references it in the vault config.
67-135: Comprehensive initialization event validation.The test correctly validates the initialization event and all configuration fields. The
msgSenderbeingaddress(0)(lines 112, 129) is expected behavior when initialization occurs through proxy construction. The nestedreceiptVaultConfigfield access pattern aligns with the V2 config structure.
138-169: LGTM!The test correctly validates creating multiple vaults with different configurations and admins. All assertions properly verify the vault properties including receipt manager relationships and ownership.
53-64: The test is correctly structured and doesn't have a validation order fragility issue. Thereceipt: address(0)is a required parameter for the deployer, which internally creates and manages the Receipt instance. No changes needed.Likely an incorrect or invalid review comment.
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
10-24: Config struct and beacon setup look solidThe deployer config and use of immutable
IBeaconreferences in the constructor are clean and type‑safe. The pattern of wiring both beacons to the sameinitialOwneris reasonable as long as your upgrade policy expects a single admin for both receipt and vault implementations.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol (1)
11-12: Duplicate import ofOffchainAssetReceiptVaultConfigV2persists.This was flagged in a previous review and marked as addressed, but the duplicate import still appears on consecutive lines 11-12.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
.gas-snapshot(4 hunks)test/abstract/OffchainAssetReceiptVaultTest.sol(1 hunks)test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol(2 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.initialize.t.sol(2 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol(4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
🔇 Additional comments (12)
.gas-snapshot (1)
1-299: Auto-generated gas snapshot looks structurally consistentThis appears to be a standard Foundry
.gas-snapshotupdate reflecting the broader vault/test refactor (renamed test suites, updated μ/~metrics). The format is intact across all changed lines (properruns/gas,μ,~fields, and balanced parentheses), and nothing suggests manual corruption or malformed entries. As long as this file matches the latestforge snapshotoutput, it’s fine to keep as-is.test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol (2)
61-61: LGTM!The vault creation is simplified to use the
createVaulthelper from the base test class, aligning with the new deployer-based pattern introduced in this PR.
377-377: LGTM!Consistent use of the
createVaulthelper for vault instantiation.test/abstract/OffchainAssetReceiptVaultTest.sol (4)
12-20: LGTM!Imports are correctly updated to support the new beacon-based deployment pattern with
Clonesfor authorizer cloning and the newOffchainAssetReceiptVaultBeaconSetDeployer.
28-39: LGTM!The constructor correctly initializes the
OffchainAssetReceiptVaultBeaconSetDeployerwith the receipt and vault implementations.
41-63: LGTM!The
createVaultfunction correctly implements the new deployment pattern:
- Deploys vault via the beacon deployer
- Clones and initializes the authorizer
- Sets the authorizer on the vault under the admin context
65-81: LGTM!The
getReceiptfunction correctly parses the V2 event structure. TheeventFoundflag is tracked but the function returnsReceiptContract(address(0))if not found, which is acceptable for test utility code since the calling test would fail on subsequent operations anyway.test/src/concrete/vault/ERC20PriceOracleReceiptVault.initialize.t.sol (2)
15-55: LGTM!The test function is correctly updated to validate the V2 event emission with proper event topic signature and config decoding.
58-74: LGTM!Assertions correctly access config properties through the new
receiptVaultConfigpath, consistent with the V2 struct layout.test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol (3)
20-43: LGTM!The test correctly creates beacon proxies directly to test the
ZeroInitialAdminrevert condition during initialization, bypassing the deployer's validation.
45-65: LGTM!The test correctly validates the
NonZeroAssetrevert condition using the deployer with the V2 config structure.
67-140: LGTM!The test comprehensively validates the V2 initialization event emission and the
AuthorizerSetevent. All assertions correctly use thereceiptVaultConfigpath for config property access.
test/src/concrete/vault/ERC20PriceOracleReceiptVault.initialize.t.sol
Outdated
Show resolved
Hide resolved
test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
🔇 Additional comments (3)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol (3)
1-10: LGTM!Imports are appropriate for the clone deployer pattern. Using OpenZeppelin's Clones library is the correct approach for minimal proxy deployments.
12-16: LGTM!The config struct is clean and minimal, capturing only the necessary implementation addresses.
22-27: LGTM!The constructor properly validates that implementation addresses are non-zero before storing them.
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
.gas-snapshot(4 hunks)src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol(1 hunks)src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)src/error/ErrDeployer.sol(1 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.initialize.t.sol(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
🔇 Additional comments (5)
.gas-snapshot (1)
1-299: Gas snapshot updates reflect test refactoring.The re-baselined metrics and renamed test groups align with the V2 config migration and deployer-based test flows described in the PR summary. The changes appear consistent with the structural refactoring.
Minor: The file is missing a newline at the end (Line 299), which may cause git warnings.
test/src/concrete/vault/ERC20PriceOracleReceiptVault.initialize.t.sol (2)
13-22: Test correctly updated for V2 initialization event.The event topic hash and config type changes properly align with the V2 configuration structure. The test captures the new event signature with nested config fields.
39-72: Assertions comprehensively validate V2 initialization.The test correctly verifies:
- Event sender is the deployer
- Vault name/symbol match config
- Asset is correctly set
- Receipt is non-zero and linked to vault
- Price oracle is configured
- Receipt's manager is the vault
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (2)
40-63: Deployment flow correctly mirrors the clone deployer pattern.The beacon proxy deployment follows the same correct initialization order:
- Create both proxies (uninitialized)
- Initialize receipt with vault as manager
- Update config with receipt address
- Initialize vault with complete config
- Return the vault
Custom errors are used consistently for all failure cases.
27-38: No validation needed forinitialOwner. In OpenZeppelin v5,UpgradeableBeaconautomatically reverts ifinitialOwnerisaddress(0)through its inheritedOwnableconstructor, so the misconfiguration scenario described is already prevented.
| // SPDX-License-Identifier: LicenseRef-DCL-1.0 | ||
| // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd | ||
| pragma solidity ^0.8.25; | ||
|
|
||
| /// Thrown when constructing a deployer with a zero receipt implementation | ||
| /// address. | ||
| error ZeroReceiptImplementation(); | ||
|
|
||
| /// Thrown when constructing a deployer with a zero vault implementation address. | ||
| error ZeroVaultImplementation(); | ||
|
|
||
| /// Thrown when attempting to initialize with a non-zero receipt address. | ||
| /// @param receipt The receipt address that is not zero in the initialization | ||
| /// config. | ||
| error InitializeNonZeroReceipt(address receipt); | ||
|
|
||
| error InitializeReceiptFailed(); | ||
|
|
||
| error InitializeVaultFailed(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Error definitions are well-structured.
The custom errors provide clear, gas-efficient revert reasons for deployer validation failures. The InitializeNonZeroReceipt error helpfully includes the problematic address for debugging.
Minor observations:
InitializeReceiptFailedandInitializeVaultFailed(lines 17-19) lack NatSpec comments unlike the other errors.- The pragma uses
^0.8.25while other files in this PR use=0.8.25. Consider aligning for consistency.
🤖 Prompt for AI Agents
In src/error/ErrDeployer.sol lines 1 to 19, update the file to add NatSpec
comment lines for the InitializeReceiptFailed and InitializeVaultFailed errors
(mirroring the style used for the other custom errors) and change the pragma
from ^0.8.25 to =0.8.25 to match the project's Solidity version pinning; keep
the comments concise, describing when each error is thrown (receipt
initialization failure and vault initialization failure respectively).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thedavidmeister, noted! Let me know if you'd like any clarification on the suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
41-63: Consider emitting a deployment event for easier off‑chain trackingThe deployment flow and error handling look correct: zero‑receipt guard, typed beacon proxies, and explicit
ICLONEABLE_V2_SUCCESSchecks with custom errors.For observability and indexing, consider emitting an event after both initializations succeed, e.g.:
event OffchainAssetReceiptVaultDeployed( address indexed vault, address indexed receipt, address indexed deployer ); // after successful initializes: emit OffchainAssetReceiptVaultDeployed( address(offchainAssetReceiptVault), address(receipt), msg.sender );This makes it much easier to discover and track vault/receipt pairs off‑chain, especially now that creation is beacon‑driven rather than factory‑based.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)
🔇 Additional comments (1)
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
18-27: Config struct and typed beacon references look solidUsing concrete
Receipt/OffchainAssetReceiptVaulttypes in the config andIBeacon-typed immutable references keeps the deployer API clear and type-safe while still exposing the underlying beacons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol(4 hunks)
🔇 Additional comments (2)
test/src/concrete/vault/OffchainAssetReceiptVault.initialize.t.sol (2)
96-106: VerifyOffchainAssetReceiptVaultInitializedV2event definition vs decoding assumptions.This loop hashes
"OffchainAssetReceiptVaultInitializedV2(address,(address,(address,string,string,address)))"and then decodeslogs[i].dataas(address, OffchainAssetReceiptVaultConfigV2). This is correct only if:
- The event has exactly two parameters with those types, and
- The first
address(msgSender) is not indexed (otherwise its value lives intopics[1], not indata).If
msgSenderisindexedin the event, you should instead:
- Read
msgSenderfromlogs[i].topics[1], and- Decode only the config struct from
logs[i].data.Please double‑check the event definition in
OffchainAssetReceiptVault.soland adjust either the signature string or the decoding accordingly if it diverges.
66-139: Good coverage of new initialization and authorizer event semantics.The new
testOffchainAssetReceiptVaultInitializedV2Eventthoroughly validates:
- The full nested
receiptVaultConfiginsideOffchainAssetReceiptVaultConfigV2.- That the deployer is recorded as
msgSenderin the init event.- That the
AuthorizerSetevent wiresalicetovault.authorizer()and that the vault is set as the receipt manager.This is a solid regression test around the new deployer/beacon-based initialization path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (3)
test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol (1)
377-377: LGTM!Consistent usage of the
createVaulthelper. This test uses a real vault instance without mocking, which provides good integration test coverage.src/error/ErrDeployer.sol (1)
3-24: Custom errors are solid; minor consistency nits on pragma andZeroBeaconOwnerThe error set cleanly captures deployer failure modes, and the added NatSpec on
InitializeReceiptFailed/InitializeVaultFailedis helpful.Two small follow‑ups:
- Line [3]: pragma uses
^0.8.25while the rest of this PR appears to pin=0.8.25. Consider aligning for consistency and to avoid accidental compiler drift.- Lines [12-14]:
ZeroBeaconOwneris documented as “when the beacon owner is set to the zero address”. InOffchainAssetReceiptVaultBeaconSetDeployer, it’s currently used forconfig.initialAdmin == address(0)rather than the beacon owner itself. Either:
- Add a dedicated check for
config.initialOwner == address(0)in that constructor so this error actually covers the beacon-owner case, and use a separate error (e.g.ZeroInitialAdmin) for the admin; or- Broaden/rename this error’s docs if you intend it to cover both beacon owner and admin being zero.
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol (1)
31-42: Still no explicit guard on zero beacon owner;ZeroBeaconOwnersemantics are inconsistentThe constructor validates implementation addresses but still allows
config.initialOwner == address(0)to flow intoUpgradeableBeacon. In that case OZ’sOwnablewill revert with its own error instead of your deployer‑specificZeroBeaconOwner, which contradicts the error’s NatSpec (“when the beacon owner is set to the zero address”). At the same time,ZeroBeaconOwneris currently used innewOffchainAssetReceiptVaultforconfig.initialAdmin == address(0), which isn’t about the beacon owner.I’d strongly recommend:
- Guarding
initialOwnerexplicitly in the constructor so the intended custom error is actually used:constructor(OffchainAssetReceiptVaultBeaconSetDeployerConfig memory config) { if (address(config.initialReceiptImplementation) == address(0)) { revert ZeroReceiptImplementation(); } if (address(config.initialOffchainAssetReceiptVaultImplementation) == address(0)) { revert ZeroVaultImplementation(); } + + if (config.initialOwner == address(0)) { + revert ZeroBeaconOwner(); + } I_RECEIPT_BEACON = new UpgradeableBeacon(address(config.initialReceiptImplementation), config.initialOwner); I_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON = new UpgradeableBeacon(address(config.initialOffchainAssetReceiptVaultImplementation), config.initialOwner); }
- Clarifying how you want to handle
config.initialAdmin == address(0)in Line [52]: either keep that check but introduce/use a more precise error for an invalid admin, or broaden the meaning/doc ofZeroBeaconOwnerif you really intend to reuse it for both beacon owner and admin.Also applies to: 52-52
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
.gas-snapshot(4 hunks)src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)src/error/ErrDeployer.sol(1 hunks)test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol(3 hunks)test/src/concrete/receipt/Receipt.metadata.t.sol(1 hunks)test/src/concrete/receipt/Receipt.t.sol(1 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.mint.t.sol(1 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.redeem.t.sol(1 hunks)test/src/concrete/vault/ERC20PriceOracleReceiptVault.withdraw.t.sol(1 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.confiscateReceipt.t.sol(1 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.handler.t.sol(1 hunks)test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
🔇 Additional comments (13)
test/src/concrete/receipt/Receipt.metadata.t.sol (1)
7-7: LGTM! Import path normalized.The import path has been updated from a deep relative path to a root-relative path, improving maintainability and consistency with the broader project refactoring.
test/src/concrete/receipt/Receipt.t.sol (1)
5-5: LGTM! Import paths normalized.Both import paths have been updated from deep relative paths to root-relative paths, improving code maintainability and consistency with the broader project refactoring.
Also applies to: 9-9
.gas-snapshot (1)
1-299: Auto-generated gas snapshot reflects test refactoring.This file is generated by
forge snapshotand captures gas metrics for all tests. The changes align with the broader PR refactoring (V2 config structures, deployer patterns, namespace reorganization). Gas values appear within expected ranges for vault operations.Consider committing this file only after the PR stabilizes to avoid churn from intermediate test changes.
test/src/concrete/vault/ERC20PriceOracleReceiptVault.mint.t.sol (1)
5-15: LGTM! Import path refactoring is clean and consistent.The import paths have been successfully updated from relative paths to module-style aliases (e.g.,
"src/..."), which improves maintainability and aligns with the broader proxy-agnostic refactor. No behavioral changes to the test logic.test/src/concrete/vault/ERC20PriceOracleReceiptVault.withdraw.t.sol (1)
5-14: LGTM! Import path refactoring is clean and consistent.The import paths have been successfully updated from relative paths to module-style aliases, matching the same pattern applied across the test suite. No behavioral changes to the test logic.
test/src/concrete/vault/ERC20PriceOracleReceiptVault.redeem.t.sol (1)
5-14: LGTM! Import path refactoring is clean and consistent.The import paths have been successfully updated from relative paths to module-style aliases, maintaining consistency across all three test files. No behavioral changes to the test logic.
test/src/concrete/vault/OffchainAssetReceiptVault.ownerFreezeUntil.t.sol (2)
9-17: Updated imports correctly align with new vault and receipt shapesThe switch to importing
OffchainAssetReceiptVault,IReceiptV3, and the role constants fromOffchainAssetReceiptVaultAuthorizerV1matches how they’re used in the tests and keeps this file consistent with the V2/proxy‑agnostic setup. No issues from a correctness or style perspective here.
25-26: Constructor’s use ofcreateVaulthelper looks soundUsing
createVault(sAlice, "vault", "VLT")and storing the result asIOwnerFreezableV1cleanly abstracts away the deploy mechanics while preserving the owner‑freezable interface this test relies on. The later casts toOffchainAssetReceiptVaultviaaddress(sOwnerFreezable)are consistent with a proxy‑agnostic design, assumingcreateVaultalways returns the expected vault implementation.If you haven’t already, it’s worth double‑checking that all other tests using
createVaultagree on the share name/symbol and thatcreateVaultalways yields anOffchainAssetReceiptVault(or compatible proxy) so this downcast remains valid.test/src/concrete/vault/OffchainAssetReceiptVault.confiscateReceipt.t.sol (2)
11-11: Unable to complete verification due to repository access limitations.
10-10: Import paths updated to project-relative aliases.The import paths have been refactored from relative paths (
../../../../src/...) to root-relative paths (src/...,test/...). All imported source files exist at their expected locations and resolve correctly. No additional configuration changes are required.test/src/concrete/authorize/OffchainAssetReceiptVaultPaymentMintAuthorizerV1.deposit.t.sol (2)
17-17: LGTM!The import is necessary to support the type declaration for
createVaultreturn values used in the test methods.
61-61:createVaulthelper is properly defined and correctly used.The
createVaultmethod is defined in the parent classOffchainAssetReceiptVaultTestwith the signaturefunction createVault(address admin, string memory shareName, string memory shareSymbol) internal returns (OffchainAssetReceiptVault). The usage at line 61 matches the expected signature and is properly inherited through the test class hierarchy.test/src/concrete/vault/OffchainAssetReceiptVault.handler.t.sol (1)
5-16: Import path refactor looks correctSwitching to root-relative
src/...imports for the vault, receipt, and authorizer aligns with the project’s convention and doesn’t affect test behavior. No further issues spotted in this file.
src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol(1 hunks)src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.sol(1 hunks)test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newERC20PriceOracleReceiptVault.t.sol(1 hunks)
🔇 Additional comments (1)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol (1)
38-62: This comment is based on an incorrect assumption.
ERC20PriceOracleReceiptVaultConfigV2does not contain aninitialAdminfield. The struct only includesIPriceOracleV2 priceOracleandReceiptVaultConfigV2 receiptVaultConfig. The comparison withOffchainAssetReceiptVaultBeaconSetDeployeris invalid because they use different configuration structures designed for different deployment patterns—the beacon deployer'sOffchainAssetReceiptVaultConfigV2hasinitialAdmin, while the clone deployer's config does not. No validation change is needed.Likely an incorrect or invalid review comment.
| function testNewOffchainAssetReceiptVault(OffchainAssetReceiptVaultConfigV2 memory config) external { | ||
| vm.assume(config.receiptVaultConfig.receipt == address(0)); | ||
| vm.assume(config.initialAdmin != address(0)); | ||
| vm.assume(config.receiptVaultConfig.asset == address(0)); | ||
|
|
||
| ReceiptContract receiptImplementation = new ReceiptContract(); | ||
| OffchainAssetReceiptVault offchainAssetReceiptVaultImplementation = new OffchainAssetReceiptVault(); | ||
| OffchainAssetReceiptVaultBeaconSetDeployer deployer = new OffchainAssetReceiptVaultBeaconSetDeployer( | ||
| OffchainAssetReceiptVaultBeaconSetDeployerConfig({ | ||
| initialOwner: address(this), | ||
| initialReceiptImplementation: address(receiptImplementation), | ||
| initialOffchainAssetReceiptVaultImplementation: address(offchainAssetReceiptVaultImplementation) | ||
| }) | ||
| ); | ||
|
|
||
| // expectEmit | ||
| OffchainAssetReceiptVault offchainAssetReceiptVault = deployer.newOffchainAssetReceiptVault(config); | ||
|
|
||
| assertEq( | ||
| address(OffchainAssetReceiptVault(payable(offchainAssetReceiptVault)).receipt().manager()), | ||
| address(offchainAssetReceiptVault) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider expanding test assertions for more comprehensive coverage.
The test currently only verifies that the receipt's manager equals the vault address. Consider adding assertions to verify:
- The vault's admin is correctly set to
config.initialAdmin - The receipt address is non-zero and correctly set
- The vault's asset configuration matches the provided config
- The returned vault address is non-zero
Example additions:
assertEq(offchainAssetReceiptVault.hasRole(offchainAssetReceiptVault.DEFAULT_ADMIN_ROLE(), config.initialAdmin), true);
assertTrue(address(offchainAssetReceiptVault.receipt()) != address(0));🤖 Prompt for AI Agents
In
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newERC20PriceOracleReceiptVault.t.sol
around lines 53-75, the test only asserts the receipt's manager; expand
assertions to comprehensively validate deployment: assert the returned vault
address is non-zero, assert the vault's DEFAULT_ADMIN_ROLE is granted to
config.initialAdmin (use hasRole with assertEq/assertTrue), assert the receipt()
address is non-zero, and assert the vault's asset/config fields match
config.receiptVaultConfig (e.g., asset and any other exposed config getters) to
ensure the vault was initialized with the provided config.
...oncrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol (1)
68-75: Address the missing event verification and expand test assertions.The past review correctly identified two issues that remain unaddressed:
Missing event verification (lines 68-69): The comment
// expectEmitindicates intent but no actual verification is present. Usevm.recordLogs()to capture and verify theDeploymentevent is emitted with correct parameters.Insufficient assertions (lines 71-74): Only the receipt manager is validated. Add assertions for:
- Vault address is non-zero:
assertTrue(address(offchainAssetReceiptVault) != address(0));- Receipt address is non-zero:
assertTrue(address(offchainAssetReceiptVault.receipt()) != address(0));- Initial admin role is granted:
assertTrue(offchainAssetReceiptVault.hasRole(offchainAssetReceiptVault.DEFAULT_ADMIN_ROLE(), config.initialAdmin));Based on learnings, past review feedback should be addressed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
.gas-snapshot(4 hunks)test/src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.newERC20PriceOracleReceiptVault.t.sol(1 hunks)test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
🔇 Additional comments (2)
.gas-snapshot (1)
1-311: Auto-generated gas snapshot – changes are expected.This file is automatically generated by Forge and contains baseline gas consumption metrics for test cases. The complete regeneration (all lines changed) is normal after refactoring. The minor variations in gas consumption across tests reflect the architectural changes from factory-based deployment to beacon proxies and clone patterns mentioned in the PR summary.
Note: Ensure that:
- Test suite passes with the new gas baselines
- No unexpected major gas increases have been introduced
- The changes align with the proxy-agnostic refactoring objectives
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol (1)
56-56: The assumption is correct by design — OffchainAssetReceiptVault requires zero asset address.The
vm.assume(config.receiptVaultConfig.asset == address(0))on line 56 is intentional and correct. The OffchainAssetReceiptVault contract explicitly requires the asset to be address(0), enforced by the check on line 307-308 ofOffchainAssetReceiptVault.solwhich reverts withNonZeroAsset()if a non-zero asset is provided. The contract is designed to track offchain assets only, so the zero address represents the absence of an on-chain ERC20 token.Likely an incorrect or invalid review comment.
| function testNewERC20PriceOracleReceiptVaultNonZeroReceipt(ERC20PriceOracleReceiptVaultConfigV2 memory config) | ||
| external | ||
| { | ||
| vm.assume(config.receiptVaultConfig.receipt != address(0)); | ||
| ReceiptContract receiptImplementation = new ReceiptContract(); | ||
| ERC20PriceOracleReceiptVault erc20PriceOracleReceiptVaultImplementation = new ERC20PriceOracleReceiptVault(); | ||
| ERC20PriceOracleReceiptVaultCloneDeployer deployer = new ERC20PriceOracleReceiptVaultCloneDeployer( | ||
| ERC20PriceOracleReceiptVaultCloneDeployerConfig({ | ||
| receiptImplementation: address(receiptImplementation), | ||
| erc20PriceOracleReceiptVaultImplementation: address(erc20PriceOracleReceiptVaultImplementation) | ||
| }) | ||
| ); | ||
| vm.expectRevert(abi.encodeWithSelector(InitializeNonZeroReceipt.selector, config.receiptVaultConfig.receipt)); | ||
| deployer.newERC20PriceOracleReceiptVault(config); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Move implementation deployments to setUp() for fuzz test efficiency.
Creating ReceiptContract and ERC20PriceOracleReceiptVault implementations inside the fuzz test causes them to be deployed on every fuzz iteration, which is inefficient. Move these deployments to a setUp() function and store them as contract-level state variables.
Apply this pattern:
+contract ERC20PriceOracleReceiptVaultCloneDeployerNewERC20PriceOracleReceiptVaultTest is Test {
+ ReceiptContract receiptImplementation;
+ ERC20PriceOracleReceiptVault erc20PriceOracleReceiptVaultImplementation;
+ ERC20PriceOracleReceiptVaultCloneDeployer deployer;
+
+ function setUp() public {
+ receiptImplementation = new ReceiptContract();
+ erc20PriceOracleReceiptVaultImplementation = new ERC20PriceOracleReceiptVault();
+ deployer = new ERC20PriceOracleReceiptVaultCloneDeployer(
+ ERC20PriceOracleReceiptVaultCloneDeployerConfig({
+ receiptImplementation: address(receiptImplementation),
+ erc20PriceOracleReceiptVaultImplementation: address(erc20PriceOracleReceiptVaultImplementation)
+ })
+ );
+ }
+
function testNewERC20PriceOracleReceiptVaultNonZeroReceipt(ERC20PriceOracleReceiptVaultConfigV2 memory config)
external
{
vm.assume(config.receiptVaultConfig.receipt != address(0));
- ReceiptContract receiptImplementation = new ReceiptContract();
- ERC20PriceOracleReceiptVault erc20PriceOracleReceiptVaultImplementation = new ERC20PriceOracleReceiptVault();
- ERC20PriceOracleReceiptVaultCloneDeployer deployer = new ERC20PriceOracleReceiptVaultCloneDeployer(
- ERC20PriceOracleReceiptVaultCloneDeployerConfig({
- receiptImplementation: address(receiptImplementation),
- erc20PriceOracleReceiptVaultImplementation: address(erc20PriceOracleReceiptVaultImplementation)
- })
- );
vm.expectRevert(abi.encodeWithSelector(InitializeNonZeroReceipt.selector, config.receiptVaultConfig.receipt));
deployer.newERC20PriceOracleReceiptVault(config);
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
test/src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.newERC20PriceOracleReceiptVault.t.sol
around lines 21-35, the test deploys ReceiptContract and
ERC20PriceOracleReceiptVault inside the fuzz test causing repeated deployments;
move those deployments into a setUp() function and store the deployed addresses
as contract-level state variables (e.g., receiptImplementation and
erc20PriceOracleReceiptVaultImplementation) initialized once in setUp(), then
update the test to use those stored variables when constructing the
ERC20PriceOracleReceiptVaultCloneDeployer so the fuzz iterations reuse the same
implementations.
| function testNewERC20PriceOracleReceiptVaultSuccess(ERC20PriceOracleReceiptVaultConfigV2 memory config) external { | ||
| vm.assume(config.receiptVaultConfig.receipt == address(0)); | ||
| ReceiptContract receiptImplementation = new ReceiptContract(); | ||
| ERC20PriceOracleReceiptVault erc20PriceOracleReceiptVaultImplementation = new ERC20PriceOracleReceiptVault(); | ||
| ERC20PriceOracleReceiptVaultCloneDeployer deployer = new ERC20PriceOracleReceiptVaultCloneDeployer( | ||
| ERC20PriceOracleReceiptVaultCloneDeployerConfig({ | ||
| receiptImplementation: address(receiptImplementation), | ||
| erc20PriceOracleReceiptVaultImplementation: address(erc20PriceOracleReceiptVaultImplementation) | ||
| }) | ||
| ); | ||
| ERC20PriceOracleReceiptVault vault = deployer.newERC20PriceOracleReceiptVault(config); | ||
| assert(address(vault) != address(0)); | ||
| assert(vault.asset() == config.receiptVaultConfig.asset); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Expand test assertions for comprehensive deployment validation.
The success test only verifies the vault address is non-zero and the asset matches. Consider adding assertions to validate:
- The receipt address is non-zero:
assert(address(vault.receipt()) != address(0)); - The receipt's manager is correctly set to the vault:
assertEq(address(vault.receipt().manager()), address(vault)); - Other critical config fields are properly initialized (e.g., priceOracle if exposed via a getter)
This ensures the deployer correctly wires all components together.
🤖 Prompt for AI Agents
In
test/src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.newERC20PriceOracleReceiptVault.t.sol
around lines 37 to 50, the test only checks that the vault address is non-zero
and asset matches; add assertions to more fully validate deployment: assert the
vault.receipt() address is non-zero, assert the receipt's manager equals the
deployed vault address, and assert any other exposed critical fields (e.g.,
priceOracle getter) match the config values; insert these additional assertions
after the existing asserts so the test fails if components are not wired
correctly.
| function testNewOffchainAssetReceiptVaultNonZeroReceipt(OffchainAssetReceiptVaultConfigV2 memory config) external { | ||
| vm.assume(config.receiptVaultConfig.receipt != address(0)); | ||
| vm.assume(config.initialAdmin != address(0)); | ||
|
|
||
| ReceiptContract receiptImplementation = new ReceiptContract(); | ||
| OffchainAssetReceiptVault offchainAssetReceiptVaultImplementation = new OffchainAssetReceiptVault(); | ||
| OffchainAssetReceiptVaultBeaconSetDeployer deployer = new OffchainAssetReceiptVaultBeaconSetDeployer( | ||
| OffchainAssetReceiptVaultBeaconSetDeployerConfig({ | ||
| initialOwner: address(this), | ||
| initialReceiptImplementation: address(receiptImplementation), | ||
| initialOffchainAssetReceiptVaultImplementation: address(offchainAssetReceiptVaultImplementation) | ||
| }) | ||
| ); | ||
| vm.expectRevert(abi.encodeWithSelector(InitializeNonZeroReceipt.selector, config.receiptVaultConfig.receipt)); | ||
| deployer.newOffchainAssetReceiptVault(config); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Move implementation and deployer setup to setUp() for test efficiency.
All three test functions create ReceiptContract, OffchainAssetReceiptVault, and OffchainAssetReceiptVaultBeaconSetDeployer instances. For fuzz tests, this results in redundant deployments on every iteration. Extract the common setup into a setUp() function.
Example:
+contract OffchainAssetReceiptVaultBeaconSetDeployerNewOffchainAssetReceiptVaultTest is Test {
+ ReceiptContract receiptImplementation;
+ OffchainAssetReceiptVault offchainAssetReceiptVaultImplementation;
+ OffchainAssetReceiptVaultBeaconSetDeployer deployer;
+
+ function setUp() public {
+ receiptImplementation = new ReceiptContract();
+ offchainAssetReceiptVaultImplementation = new OffchainAssetReceiptVault();
+ deployer = new OffchainAssetReceiptVaultBeaconSetDeployer(
+ OffchainAssetReceiptVaultBeaconSetDeployerConfig({
+ initialOwner: address(this),
+ initialReceiptImplementation: address(receiptImplementation),
+ initialOffchainAssetReceiptVaultImplementation: address(offchainAssetReceiptVaultImplementation)
+ })
+ );
+ }Also applies to: 34-51, 53-75
🤖 Prompt for AI Agents
In
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol
around lines 17-32, the test repeatedly constructs ReceiptContract,
OffchainAssetReceiptVault, and OffchainAssetReceiptVaultBeaconSetDeployer for
each fuzz iteration; move these common instantiations into a setUp() function by
adding state-level variables for receiptImplementation,
offchainAssetReceiptVaultImplementation, and deployer, initialize them once in
setUp(), and then remove the duplicate construction code from this test (and the
other test blocks at lines 34-51 and 53-75) so the tests reuse the
pre-initialized instances to improve fuzz performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
test/src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.newERC20PriceOracleReceiptVault.t.sol (2)
21-35: Move implementation deployments to setUp() for fuzz test efficiency.Creating
ReceiptContractandERC20PriceOracleReceiptVaultimplementations inside the fuzz test causes them to be deployed on every fuzz iteration, which is inefficient. Move these deployments to asetUp()function and store them as contract-level state variables.
37-76: Move implementation deployments to setUp() and expand test assertions.Two issues:
- Same as the previous test: implementations are deployed on every fuzz iteration. Move to
setUp().- The test only verifies the vault address is non-zero and the asset matches. Consider adding assertions to validate:
- The receipt address is non-zero:
assert(address(vault.receipt()) != address(0));- The receipt's manager is correctly set to the vault:
assertEq(address(vault.receipt().manager()), address(vault));- Other critical config fields if exposed via getters
This ensures the deployer correctly wires all components together.
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol (2)
17-98: Extract common setup to setUp() function for efficiency and maintainability.All three test functions create identical implementations (
ReceiptContract,OffchainAssetReceiptVault) and deployer instances. For fuzz tests, this results in redundant deployments on every iteration, impacting performance and violating DRY principles. This was previously flagged in past reviews.Apply this diff to move the common setup:
contract OffchainAssetReceiptVaultBeaconSetDeployerNewOffchainAssetReceiptVaultTest is Test { + ReceiptContract receiptImplementation; + OffchainAssetReceiptVault offchainAssetReceiptVaultImplementation; + OffchainAssetReceiptVaultBeaconSetDeployer deployer; + + function setUp() public { + receiptImplementation = new ReceiptContract(); + offchainAssetReceiptVaultImplementation = new OffchainAssetReceiptVault(); + deployer = new OffchainAssetReceiptVaultBeaconSetDeployer( + OffchainAssetReceiptVaultBeaconSetDeployerConfig({ + initialOwner: address(this), + initialReceiptImplementation: address(receiptImplementation), + initialOffchainAssetReceiptVaultImplementation: address(offchainAssetReceiptVaultImplementation) + }) + ); + } + function testNewOffchainAssetReceiptVaultNonZeroReceipt(OffchainAssetReceiptVaultConfigV2 memory config) external { vm.assume(config.receiptVaultConfig.receipt != address(0)); vm.assume(config.initialAdmin != address(0)); - ReceiptContract receiptImplementation = new ReceiptContract(); - OffchainAssetReceiptVault offchainAssetReceiptVaultImplementation = new OffchainAssetReceiptVault(); - OffchainAssetReceiptVaultBeaconSetDeployer deployer = new OffchainAssetReceiptVaultBeaconSetDeployer( - OffchainAssetReceiptVaultBeaconSetDeployerConfig({ - initialOwner: address(this), - initialReceiptImplementation: address(receiptImplementation), - initialOffchainAssetReceiptVaultImplementation: address(offchainAssetReceiptVaultImplementation) - }) - ); vm.expectRevert(abi.encodeWithSelector(InitializeNonZeroReceipt.selector, config.receiptVaultConfig.receipt)); deployer.newOffchainAssetReceiptVault(config); }Remove the duplicate setup code from the other two test functions similarly.
53-98: Expand test assertions to comprehensively validate deployment.The test currently only verifies that the receipt's manager equals the vault address. As flagged in previous reviews, consider adding assertions to verify:
- The returned vault address is non-zero
- The receipt address is non-zero
- The vault's
DEFAULT_ADMIN_ROLEis correctly granted toconfig.initialAdmin- The receipt reference is correctly stored in the vault
Add these assertions after line 97:
assertEq( address(OffchainAssetReceiptVault(payable(offchainAssetReceiptVault)).receipt().manager()), address(offchainAssetReceiptVault) ); + + assertTrue(address(offchainAssetReceiptVault) != address(0), "Vault address should be non-zero"); + assertTrue(address(offchainAssetReceiptVault.receipt()) != address(0), "Receipt address should be non-zero"); + assertTrue( + offchainAssetReceiptVault.hasRole( + offchainAssetReceiptVault.DEFAULT_ADMIN_ROLE(), + config.initialAdmin + ), + "Admin role should be granted to initialAdmin" + ); }
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol(1 hunks)test/src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.newERC20PriceOracleReceiptVault.t.sol(1 hunks)test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-legal)
- GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
🔇 Additional comments (3)
src/concrete/deploy/ERC20PriceOracleReceiptVaultCloneDeployer.sol (2)
33-38: LGTM! Constructor validation is correct.The zero-address checks with custom errors provide clear error handling, and the public immutable storage pattern is appropriate for implementation addresses.
40-66: LGTM! Deployment flow is correctly ordered and error handling is comprehensive.The initialization sequence properly establishes the bidirectional relationship:
- Receipt is initialized with the vault as its manager
- Config is updated with the receipt address
- Vault is initialized with the complete config
Each step includes appropriate error handling with custom errors, and the event emission provides good observability for off-chain indexing.
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol (1)
59-59: No action needed—zero asset address is required by the OffchainAssetReceiptVault.The assumption that
config.receiptVaultConfig.asset == address(0)is correct. The vault explicitly enforces this requirement by reverting withNonZeroAsset()if a non-zero asset is provided. This is intentional design for offchain asset vaults, not a validation bypass.
| vm.stopPrank(); | ||
|
|
||
| bool eventFound = false; | ||
| bytes32 eventTopic = keccak256("OffchainAssetReceiptVaultBeaconSetDeployerDeployment(address,address,address)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Replace manual event topic hash with type-safe construction.
Manually constructing the event topic hash with a string literal is error-prone. A typo in the event signature would cause the test to silently fail to find the event without detecting the mismatch.
Apply this diff to use the actual event selector from the deployer:
- bytes32 eventTopic = keccak256("OffchainAssetReceiptVaultBeaconSetDeployerDeployment(address,address,address)");
+ bytes32 eventTopic = OffchainAssetReceiptVaultBeaconSetDeployer.Deployment.selector;Alternatively, if the event is not exposed as a selector, reference it via the interface or use the event declaration directly to ensure type safety.
🤖 Prompt for AI Agents
test/src/concrete/deploy/OffchainAssetReceiptVaultBeaconSetDeployer.newOffchainAssetReceiptVault.t.sol
around line 78: currently the event topic is built from a hard-coded string
literal; replace this with a type-safe construction by referencing the deployer
contract's event instead of a raw string. Import or reference the
OffchainAssetReceiptVaultBeaconSetDeployer contract/interface and compute the
topic from the actual event declaration (e.g., derive the topic from the
contract's event selector/ABI) so the test uses the contract-defined event
signature rather than a manual keccak256 string.
Motivation
Solution
Checks
By submitting this for review, I'm confirming I've done the following:
Summary by CodeRabbit
New Features
Refactor
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.