Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f34cd17
chore: upgrade checkout to v5
jacopo-eth Aug 29, 2025
9b8a80a
fix: contracts
jacopo-eth Sep 9, 2025
94e04a9
access control init
jacopo-eth Sep 14, 2025
213f372
wip
jacopo-eth Sep 14, 2025
5119cc5
access control final draft
jacopo-eth Sep 14, 2025
211d10e
cleanup
jacopo-eth Sep 15, 2025
a6eb47e
multi-actions support: init
jacopo-eth Sep 17, 2025
faea2fd
multi-pricing init
jacopo-eth Sep 22, 2025
a1ec6fb
contracts wip
jacopo-eth Sep 24, 2025
bc9b0cc
hook versioning
jacopo-eth Sep 28, 2025
e07e464
fix tests
jacopo-eth Sep 29, 2025
ff11933
fix: NFTGated hook
jacopo-eth Sep 29, 2025
df8dfb9
update hooks tests
jacopo-eth Sep 29, 2025
ce1851e
indexer: update tests wip
jacopo-eth Oct 1, 2025
4f2236f
indexer: add hooks tests
jacopo-eth Oct 2, 2025
91de988
indexer: final
jacopo-eth Oct 2, 2025
e06a7e4
fixes
jacopo-eth Oct 2, 2025
0c13914
update hooks contracts with support for new interfaces
jacopo-eth Oct 4, 2025
7a3e3a2
fixes
jacopo-eth Oct 5, 2025
7243632
NFTDiscount tests
jacopo-eth Oct 5, 2025
8f86ed2
update WriteAddresses logic
jacopo-eth Oct 5, 2025
7a586f3
fix: ScriptUtils
jacopo-eth Oct 5, 2025
b345c2e
indexer: add support for additional hooks
jacopo-eth Oct 5, 2025
04c1fe9
slicer pricing strategies final
jacopo-eth Oct 29, 2025
6cf8a42
product type actions init + remove data from prodtype and slicer hooks
jacopo-eth Oct 29, 2025
198e170
fix hooks
jacopo-eth Nov 2, 2025
95922d4
update action hooks to support product type and slicer
jacopo-eth Nov 3, 2025
d1beda5
added product type and slicer action tests
jacopo-eth Nov 3, 2025
b7af93f
nit
jacopo-eth Nov 3, 2025
d22f277
fix: generated-hooks-types
jacopo-eth Nov 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/subtree-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # gh picks this up automatically
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with: {fetch-depth: 0} # full history, just in case

- name: Ensure PR exists
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive

Expand Down
132 changes: 93 additions & 39 deletions deployments/addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,132 @@
"actions": {
"Allowlisted": [
{
"address": "0x157428DD791E03c20880D22C3dA2B66A36B5cF26",
"blockNumber": 33510607,
"paramsSchema": "bytes32 merkleRoot",
"transactionHash": "0x6af9ac700f1c9a38de57fa4bc13262162d9b674649fd417ccd50237b6cfbc178"
"address": "0x87f726ac5D1023919840bebde2Da2efb5Da816ad",
"blockNumber": 36441333,
"configureProductSchema": "bytes32 merkleRoot",
"configureProductTypeSchema": "not-supported",
"configureSlicerSchema": "not-supported",
"onProductPurchaseSchema": "",
"productPriceSchema": "not-supported",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0x57419dee52082559db1d966b1b139bb79ac59c4533de43153dd11fda30b765c1"
}
],
"ERC20Gated": [
{
"address": "0x26A1C86B555013995Fc72864D261fDe984752E7c",
"blockNumber": 33558792,
"paramsSchema": "(address erc20,uint256 amount)[] erc20Gates",
"transactionHash": "0x3a7c01ede05a34280073479d5cdf1f35e41d9f08c36a71f358b9c503ccc54526"
"address": "0x247ebf608A0028DE933f1F90eE3920864D3fC621",
"blockNumber": 36440973,
"configureProductSchema": "(address erc20,uint256 amount)[] erc20Gates",
"configureProductTypeSchema": "(address erc20,uint256 amount)[] erc20Gates",
"configureSlicerSchema": "(address erc20,uint256 amount)[] erc20Gates",
"onProductPurchaseSchema": "",
"productPriceSchema": "not-supported",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0xac40db0f5c63ec520e671db10b018018900a332d563c99bc9828a6cc20b48863"
}
],
"ERC20Mint": [
{
"address": "0x67f9799FaC1D53C63217BEE47f553150F5BB0836",
"blockNumber": 33520592,
"paramsSchema": "string name,string symbol,uint256 premintAmount,address premintReceiver,bool revertOnMaxSupplyReached,uint256 maxSupply,uint256 tokensPerUnit",
"transactionHash": "0xfcd7e8fe47aa509afa0acdef86b741656c2602626f3258f8a83b359c665d6b04"
"address": "0x8B03B4dE7F6FD7A7BDD60Cb00aa49E144e45cdd0",
"blockNumber": 36441450,
"configureProductSchema": "string name,string symbol,uint256 premintAmount,address premintReceiver,bool revertOnMaxSupplyReached,uint256 maxSupply,uint256 tokensPerUnit",
"configureProductTypeSchema": "string name,string symbol,uint256 premintAmount,address premintReceiver,bool revertOnMaxSupplyReached,uint256 maxSupply,uint256 tokensPerUnit",
"configureSlicerSchema": "string name,string symbol,uint256 premintAmount,address premintReceiver,bool revertOnMaxSupplyReached,uint256 maxSupply,uint256 tokensPerUnit",
"onProductPurchaseSchema": "",
"productPriceSchema": "not-supported",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0xfd77332c2aba9e05a71419b87ddb0a136f85675f7d0f13cf7c46c3e65c99f44c"
}
],
"ERC721Mint": [
{
"address": "0x2b6488115FAa50142E140172CbCd60e6370675F7",
"blockNumber": 33511082,
"paramsSchema": "string name,string symbol,address royaltyReceiver,uint256 royaltyFraction,string baseURI,string tokenURI,bool revertOnMaxSupplyReached,uint256 maxSupply",
"transactionHash": "0x4981b3b67c0b8abe6a942b3ca86643f2b1dfdbcce59d6c819ad20a82814956e0"
"address": "0x48eAf12a1dC2a6dfACcb4C03F381B07ad5D5961C",
"blockNumber": 36441490,
"configureProductSchema": "string name,string symbol,address royaltyReceiver,uint256 royaltyFraction,string baseURI,string tokenURI,bool revertOnMaxSupplyReached,uint256 maxSupply",
"configureProductTypeSchema": "string name,string symbol,address royaltyReceiver,uint256 royaltyFraction,string baseURI,string tokenURI,bool revertOnMaxSupplyReached,uint256 maxSupply",
"configureSlicerSchema": "string name,string symbol,address royaltyReceiver,uint256 royaltyFraction,string baseURI,string tokenURI,bool revertOnMaxSupplyReached,uint256 maxSupply",
"onProductPurchaseSchema": "",
"productPriceSchema": "not-supported",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0x4851d2daedfa5de5a6a60a44fb9709e8c865039660c373d6d96f06c4ec2369f5"
}
],
"NFTGated": [
{
"address": "0xD4eF7A46bF4c58036eaCA886119F5230e5a2C25d",
"blockNumber": 33563508,
"paramsSchema": "(address nft,uint8 nftType,uint80 id,uint8 minQuantity)[] nftGates,uint256 minOwned",
"transactionHash": "0x9dd101a6155b432849cb33f65c5d4b9f6875e6b1e7bf806005a8a6b0d070f634"
"address": "0x560463f7bF3DFDB4Cff4f96c3399313d610Dd349",
"blockNumber": 36441510,
"configureProductSchema": "(address nft,uint8 nftType,uint80 id,uint8 minQuantity)[] gates,uint256 minOwned",
"configureProductTypeSchema": "(address nft,uint8 nftType,uint80 id,uint8 minQuantity)[] gates,uint256 minOwned",
"configureSlicerSchema": "(address nft,uint8 nftType,uint80 id,uint8 minQuantity)[] gates,uint256 minOwned",
"onProductPurchaseSchema": "",
"productPriceSchema": "not-supported",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0x3bef5e07d303ab1028a7928f9ef1ffb1613b957aff4bfe481ae79a6fd1029e2d"
}
]
},
"pricing": {
"NFTDiscount": [
"LinearVRGDAPrices": [
{
"address": "0xb830a457d2f51d4cA1136b97FB30DF6366CFe2f5",
"blockNumber": 33596708,
"paramsSchema": "(address nft,uint80 discount,uint8 minQuantity,uint8 nftType,uint256 tokenId)[] discounts",
"transactionHash": "0x966be5fa1da3fab7c5027c9acb3f118307997e30687188b4745d74fd26ad9e7e"
"address": "0x67AEdfe386a078DF350D4b1E033AB735c1fCD0C9",
"blockNumber": 36441538,
"configureProductSchema": "int184 priceDecayPercent,uint16 min,int256 perTimeUnit",
"configureProductTypeSchema": "not-supported",
"configureSlicerSchema": "not-supported",
"onProductPurchaseSchema": "not-supported",
"productPriceSchema": "",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0xd5ad41a2f994e0151edaf566e8114b703fa1843c4bbd4a8ed79b4312e22a4843"
}
],
"LinearVRGDAPrices": [
"LogisticVRGDAPrices": [
{
"address": "0xEC68E30182F4298b7032400B7ce809da613e4449",
"blockNumber": 33511188,
"paramsSchema": "(address currency,int128 targetPrice,uint128 min,int256 perTimeUnit)[] linearParams,int256 priceDecayPercent",
"transactionHash": "0xf2667ce20d07561e59c8d3e3de135bbd895c5b08bb57fe487c6c8197c91a0d73"
"address": "0x12b56C70fd76D45b578C50aD2eDB582b44d75cC1",
"blockNumber": 36441564,
"configureProductSchema": "int184 priceDecayPercent,uint16 min,int256 timescale",
"configureProductTypeSchema": "not-supported",
"configureSlicerSchema": "not-supported",
"onProductPurchaseSchema": "not-supported",
"productPriceSchema": "",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0x72fbbdd585b2fd5a2c5be0431e14c0ddee9a266f0c2c6d259dfc9b76a938122a"
}
],
"LogisticVRGDAPrices": [
"NFTDiscount": [
{
"address": "0x2b02cC8528EF18abf8185543CEC29A94F0542c8F",
"blockNumber": 33511209,
"paramsSchema": "(address currency,int128 targetPrice,uint128 min,int256 timeScale)[] logisticParams,int256 priceDecayPercent",
"transactionHash": "0x2b27380661a38b54dbccf634305622296034ddfccf5865a07fbfb7810ea41025"
"address": "0xD92820f4836b23DCe9f7696b12a5C877ec667128",
"blockNumber": 36441359,
"configureProductSchema": "(address nft,uint80 discount,uint8 minQuantity,uint8 nftType,uint256 tokenId)[] discounts",
"configureProductTypeSchema": "(address nft,uint80 discount,uint8 minQuantity,uint8 nftType,uint256 tokenId)[] discounts",
"configureSlicerSchema": "(address nft,uint80 discount,uint8 minQuantity,uint8 nftType,uint256 tokenId)[] discounts",
"onProductPurchaseSchema": "not-supported",
"productPriceSchema": "",
"productTypePriceSchema": "",
"slicerProductPriceSchema": "",
"transactionHash": "0xaf7bb92631cfa26e513b23bd48d60535244a9161e497d25d55ba139890414e3c"
}
]
},
"pricingActions": {
"FirstForFree": [
{
"address": "0x2C18D37b8229233F672bF406bCe8799BCfD43B5A",
"blockNumber": 33510960,
"paramsSchema": "uint256 usdcPrice,(address tokenAddress,uint8 tokenType,uint88 tokenId,uint8 minQuantity)[] eligibleTokens,address mintToken,uint88 mintTokenId,uint8 freeUnits",
"transactionHash": "0x8bd0b9de8edd704899210f8450096adf7f4f853030a7ba0a2f64494bc1ba726e"
"address": "0x718308153116e90393804ae7a58a8e7d5BDb6482",
"blockNumber": 36441582,
"configureProductSchema": "(address tokenAddress,uint8 tokenType,uint80 tokenId,uint8 minQuantity)[] eligibleTokens,address mintToken,uint88 mintTokenId,uint8 freeUnits",
"configureProductTypeSchema": "not-supported",
"configureSlicerSchema": "not-supported",
"onProductPurchaseSchema": "",
"productPriceSchema": "",
"productTypePriceSchema": "not-supported",
"slicerProductPriceSchema": "not-supported",
"transactionHash": "0x59033c01e7228c3f28d25ce233bb729e595515923078498e726d052f038a87aa"
}
]
}
Expand Down
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ remappings = [
"slice/=dependencies/slice-0.0.9/",
"@openzeppelin-4.8.0/=dependencies/@openzeppelin-contracts-4.8.0/",
"@openzeppelin-upgradeable-4.8.0/=dependencies/@openzeppelin-contracts-upgradeable-4.8.0/",
"solady-0.1.26/=dependencies/solady-0.1.26/",
"@erc721a/=dependencies/erc721a-4.3.0/contracts/",
"forge-std/=dependencies/forge-std-1.9.7/src/",
"@test/=test/",
Expand Down Expand Up @@ -49,6 +50,7 @@ forge-std = "1.9.7"
"@openzeppelin-contracts" = "4.8.0"
"@openzeppelin-contracts-upgradeable" = "4.8.0"
erc721a = "4.3.0"
solady = "0.1.26"

[lint]
ignore = ["test/**/*.sol","script/**/*.sol", "src/interfaces/*.sol", "src/utils/*.sol", "src/hooks/actions/actions.sol", "src/hooks/pricing/pricing.sol", "src/hooks/pricingActions/pricingActions.sol"]
Expand Down
1 change: 0 additions & 1 deletion script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {console} from "forge-std/console.sol";
import {VmSafe} from "forge-std/Vm.sol";
import {BaseScript, SetUpContractsList} from "./ScriptUtils.sol";

Expand Down
120 changes: 102 additions & 18 deletions script/ScriptUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ import {VmSafe} from "forge-std/Vm.sol";
import {ISliceCore} from "slice/interfaces/ISliceCore.sol";
import {IProductsModule} from "slice/interfaces/IProductsModule.sol";
import {IFundsModule} from "slice/interfaces/IFundsModule.sol";
import {IHookRegistry} from "slice/interfaces/hooks/IHookRegistry.sol";
import {
IProductHookRegistry,
IProductTypeHookRegistry,
ISlicerHookRegistry,
IProductPrice,
IProductTypePrice,
ISlicerProductPrice,
IProductAction
} from "slice/interfaces.sol";

/**
* Helper contract to enforce correct chain selection in scripts
Expand Down Expand Up @@ -85,7 +93,12 @@ abstract contract SetUpContractsList is Script {
struct ContractDeploymentData {
address contractAddress;
uint256 blockNumber;
string paramsSchema;
// TODO: Add other params to the json? such as configure[ProductType/Slicer]Schema and [product/productType/slicer]PriceSchema
string configureProductSchema;
string configureProductTypeSchema;
string configureSlicerSchema;
string onProductPurchaseSchema;
string productPriceSchema;
bytes32 transactionHash;
}

Expand Down Expand Up @@ -134,9 +147,7 @@ abstract contract SetUpContractsList is Script {
string[] memory arrStrings = new string[](existingData.length);
for (uint256 j = 0; j < existingData.length; j++) {
string memory idx = vm.toString(j);
vm.serializeAddress(idx, "address", existingData[j].contractAddress);
vm.serializeUint(idx, "blockNumber", existingData[j].blockNumber);
vm.serializeString(idx, "paramsSchema", existingData[j].paramsSchema);
_setFields(idx, existingData[j]);
arrStrings[j] =
vm.serializeBytes32(idx, "transactionHash", existingData[j].transactionHash);
}
Expand Down Expand Up @@ -198,6 +209,89 @@ abstract contract SetUpContractsList is Script {
vm.writeJson(vm.serializeString("addresses", firstFolder, updatedGroupJson), ADDRESSES_PATH);
}

function _setFields(string memory idx, ContractDeploymentData memory existingData) internal {
vm.serializeAddress(idx, "address", existingData.contractAddress);
vm.serializeUint(idx, "blockNumber", existingData.blockNumber);
vm.serializeString(idx, "configureProductSchema", existingData.configureProductSchema);

// Keep the previously stored schema values to avoid overwriting valid data when reserializing
vm.serializeString(idx, "configureProductTypeSchema", existingData.configureProductTypeSchema);
vm.serializeString(idx, "configureSlicerSchema", existingData.configureSlicerSchema);
vm.serializeString(idx, "onProductPurchaseSchema", existingData.onProductPurchaseSchema);
vm.serializeString(idx, "productPriceSchema", existingData.productPriceSchema);
}

function _isProductTypeHookRegistry(address contractAddress) internal view returns (bool) {
return IProductTypeHookRegistry(contractAddress).supportsInterface(type(IProductTypeHookRegistry).interfaceId);
}

function _isSlicerHookRegistry(address contractAddress) internal view returns (bool) {
return ISlicerHookRegistry(contractAddress).supportsInterface(type(ISlicerHookRegistry).interfaceId);
}

function _isProductPrice(address contractAddress) internal view returns (bool) {
return IProductPrice(contractAddress).supportsInterface(type(IProductPrice).interfaceId);
}

function _isProductTypePrice(address contractAddress) internal view returns (bool) {
return IProductTypePrice(contractAddress).supportsInterface(type(IProductTypePrice).interfaceId);
}

function _isSlicerProductPrice(address contractAddress) internal view returns (bool) {
return ISlicerProductPrice(contractAddress).supportsInterface(type(ISlicerProductPrice).interfaceId);
}

function _isProductAction(address contractAddress) internal view returns (bool) {
return IProductAction(contractAddress).supportsInterface(type(IProductAction).interfaceId);
}

function _serializeObject(string[] memory json, Tx1559 memory transaction, Receipt memory receipt)
internal
returns (string[] memory)
{
vm.serializeAddress("0", "address", transaction.contractAddress);
vm.serializeUint("0", "blockNumber", receipt.blockNumber);
vm.serializeString(
"0", "configureProductSchema", IProductHookRegistry(transaction.contractAddress).configureProductSchema()
);

vm.serializeString(
"0",
"configureProductTypeSchema",
_isProductTypeHookRegistry(transaction.contractAddress)
? IProductTypeHookRegistry(transaction.contractAddress).configureProductTypeSchema()
: "not-supported"
);

vm.serializeString(
"0",
"configureSlicerSchema",
_isSlicerHookRegistry(transaction.contractAddress)
? ISlicerHookRegistry(transaction.contractAddress).configureSlicerSchema()
: "not-supported"
);

vm.serializeString(
"0",
"onProductPurchaseSchema",
_isProductAction(transaction.contractAddress)
? IProductAction(transaction.contractAddress).onProductPurchaseSchema()
: "not-supported"
);

vm.serializeString(
"0",
"productPriceSchema",
_isProductPrice(transaction.contractAddress)
? IProductPrice(transaction.contractAddress).productPriceSchema()
: "not-supported"
);

json[0] = vm.serializeBytes32("0", "transactionHash", transaction.hash);

return json;
}

function _buildJsonArray(
string memory existingAddresses,
string memory key,
Expand All @@ -210,27 +304,17 @@ abstract contract SetUpContractsList is Script {
ContractDeploymentData[] memory existingContractAddresses =
abi.decode(contractAddressesJson, (ContractDeploymentData[]));

json = new string[](existingContractAddresses.length + 1);
vm.serializeAddress("0", "address", transaction.contractAddress);
vm.serializeUint("0", "blockNumber", receipt.blockNumber);
vm.serializeString("0", "paramsSchema", IHookRegistry(transaction.contractAddress).paramsSchema());
json[0] = vm.serializeBytes32("0", "transactionHash", transaction.hash);
json = _serializeObject(new string[](existingContractAddresses.length + 1), transaction, receipt);

for (uint256 i = 0; i < existingContractAddresses.length; i++) {
ContractDeploymentData memory existingContractAddress = existingContractAddresses[i];
string memory index = vm.toString(i + 1);

vm.serializeAddress(index, "address", existingContractAddress.contractAddress);
vm.serializeUint(index, "blockNumber", existingContractAddress.blockNumber);
vm.serializeString(index, "paramsSchema", existingContractAddress.paramsSchema);
_setFields(index, existingContractAddress);
json[i + 1] = vm.serializeBytes32(index, "transactionHash", existingContractAddress.transactionHash);
}
} else {
json = new string[](1);
vm.serializeAddress("0", "address", transaction.contractAddress);
vm.serializeUint("0", "blockNumber", receipt.blockNumber);
vm.serializeString("0", "paramsSchema", IHookRegistry(transaction.contractAddress).paramsSchema());
json[0] = vm.serializeBytes32("0", "transactionHash", transaction.hash);
json = _serializeObject(new string[](1), transaction, receipt);
}
}

Expand Down
Loading
Loading