diff --git a/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributor.sol b/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributor.sol index 62d8c09..e781607 100644 --- a/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributor.sol +++ b/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributor.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -142,7 +143,7 @@ contract ContinuousVestingMerkleDistributor_v_5_0 is Initializable, ContinuousVe require(answeredInRound > 0, "answer == 0"); require(updatedAt > 0, "round not complete"); require(answeredInRound >= roundID, "stale price"); - require(updatedAt < block.timestamp - heartbeat, "stale price"); + require(updatedAt > Math.max(block.timestamp, heartbeat) - heartbeat, "stale price"); return uint256(_price); } diff --git a/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributorFactory.sol b/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributorFactory.sol index 3ca0fb3..0deb2f0 100644 --- a/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributorFactory.sol +++ b/packages/hardhat/contracts/claim/distributor-v5/ContinuousVestingMerkleDistributorFactory.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -186,7 +187,7 @@ contract ContinuousVestingMerkleDistributorFactory_v_5_0 { require(answeredInRound > 0, "answer == 0"); require(updatedAt > 0, "round not complete"); require(answeredInRound >= roundID, "stale price"); - require(updatedAt < block.timestamp - heartbeat, "stale price"); + require(updatedAt > Math.max(block.timestamp, heartbeat) - heartbeat, "stale price"); return uint256(_price); } diff --git a/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributor.sol b/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributor.sol index 92f6a3c..147fea7 100644 --- a/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributor.sol +++ b/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributor.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -143,7 +144,7 @@ contract TrancheVestingMerkleDistributor_v_5_0 is require(answeredInRound > 0, "answer == 0"); require(updatedAt > 0, "round not complete"); require(answeredInRound >= roundID, "stale price"); - require(updatedAt < block.timestamp - heartbeat, "stale price"); + require(updatedAt > Math.max(block.timestamp, heartbeat) - heartbeat, "stale price"); return uint256(_price); } diff --git a/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributorFactory.sol b/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributorFactory.sol index 56ed2bd..ee3712b 100644 --- a/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributorFactory.sol +++ b/packages/hardhat/contracts/claim/distributor-v5/TrancheVestingMerkleDistributorFactory.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -174,7 +175,7 @@ contract TrancheVestingMerkleDistributorFactory_v_5_0 { require(answeredInRound > 0, "answer == 0"); require(updatedAt > 0, "round not complete"); require(answeredInRound >= roundID, "stale price"); - require(updatedAt < block.timestamp - heartbeat, "stale price"); + require(updatedAt > Math.max(block.timestamp, heartbeat) - heartbeat, "stale price"); return uint256(_price); } diff --git a/packages/hardhat/contracts/mocks/OracleMock.sol b/packages/hardhat/contracts/mocks/OracleMock.sol index 435524c..46c6c0c 100644 --- a/packages/hardhat/contracts/mocks/OracleMock.sol +++ b/packages/hardhat/contracts/mocks/OracleMock.sol @@ -10,7 +10,7 @@ contract OracleMock is IOracleOrL2OracleWithSequencerCheck { function latestRoundData() external - pure + view returns ( uint80 roundId, int256 answer, @@ -23,7 +23,7 @@ contract OracleMock is IOracleOrL2OracleWithSequencerCheck { 18446744073709590880, 294670000000, 1720387410, - 1720387410, + block.timestamp, 18446744073709590880 ); } diff --git a/packages/hardhat/hardhat.config.ts b/packages/hardhat/hardhat.config.ts index e953d95..5ed944c 100644 --- a/packages/hardhat/hardhat.config.ts +++ b/packages/hardhat/hardhat.config.ts @@ -3,6 +3,7 @@ import "@nomicfoundation/hardhat-toolbox"; import "@nomicfoundation/hardhat-foundry"; import "@nomicfoundation/hardhat-ignition-ethers"; import "hardhat-jest"; // Typescript +import { ethers } from 'ethers' // Add the following variables to the configuration variables. const ALCHEMY_API_KEY = vars.get("ALCHEMY_API_KEY"); @@ -14,6 +15,11 @@ const COREDAO_BLOCK_EXPLORER_API_KEY = vars.get("COREDAO_BLOCK_EXPLORER_API_KEY" const BSCSCAN_API_KEY = vars.get("BSCSCAN_API_KEY"); const SCROLL_API_KEY = vars.get("SCROLL_API_KEY"); +const phrase = process.env.TOKENSOFT_E2E_MNEMONIC || 'test test test test test test test test test test test junk' +const mnemonic = ethers.HDNodeWallet.fromPhrase(phrase).mnemonic! + +const wallet = ethers.HDNodeWallet.fromMnemonic(mnemonic, "m/44'/60'/0'/0/0") + const config: HardhatUserConfig = { solidity: { version: "0.8.21", @@ -29,6 +35,10 @@ const config: HardhatUserConfig = { enabled: false, }, networks: { + anvil: { + url: 'http://localhost:8545', + accounts: [wallet.privateKey] + }, sepolia: { url: `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`, accounts: [EVM_PRIVATE_KEY_1], diff --git a/packages/hardhat/ignition/modules/Deploy_GenericERC20.ts b/packages/hardhat/ignition/modules/Deploy_GenericERC20.ts index 80f551c..2db18fc 100644 --- a/packages/hardhat/ignition/modules/Deploy_GenericERC20.ts +++ b/packages/hardhat/ignition/modules/Deploy_GenericERC20.ts @@ -1,13 +1,25 @@ +import { ethers } from 'ethers' import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; +const mnemonic = process.env.TOKENSOFT_E2E_MNEMONIC || 'test test test test test test test test test test test junk' + const DeployGenericERC20Module = buildModule("DeployGenericERC20Module", m => { const _name = m.getParameter("_name", "My New Token"); const _symbol = m.getParameter("_symbol", "ABC"); const _decimals = m.getParameter("_decimals", 18); - const supply = m.getParameter("supply", 1_000_000_000n); + const supply = m.getParameter("supply", 1_000_000_000_000000000000000000n); const genericERC20 = m.contract("GenericERC20", [_name, _symbol, _decimals, supply]); + for (let i = 0; i < 100; i++) { + const wallet = ethers.HDNodeWallet.fromMnemonic( + ethers.HDNodeWallet.fromPhrase(mnemonic).mnemonic! + , `m/44'/60'/0'/0/${i}`) + m.call(genericERC20, 'transfer', [wallet.address, 1_000_000_000000000000000000n], { + id: `DeployGenericERC20Module_GenericERC20_transfer${wallet.address}` + }) + } + return { genericERC20 }; }); diff --git a/packages/hardhat/ignition/modules/InitializeNetworkConfigModule.ts b/packages/hardhat/ignition/modules/InitializeNetworkConfigModule.ts index 6aebbf5..e393c77 100644 --- a/packages/hardhat/ignition/modules/InitializeNetworkConfigModule.ts +++ b/packages/hardhat/ignition/modules/InitializeNetworkConfigModule.ts @@ -7,12 +7,18 @@ export default buildModule("InitializeNetworkConfigModule", m => { const { feeLevelJudgeStub } = m.useModule(FeeLevelJudgeStubModule); const { networkConfig } = m.useModule(NetworkConfigModule); + let oracleMock + + if (process.env.NETWORK_CONFIG_MOCK_ORACLE === 'true') { + oracleMock = m.contract('OracleMock') + } + m.call(networkConfig, "initialize", [ - m.getParameter("NETWORK_CONFIG_FEE_RECIPIENT"), + process.env.NETWORK_CONFIG_FEE_RECIPIENT ?? m.getParameter("NETWORK_CONFIG_FEE_RECIPIENT"), feeLevelJudgeStub, - m.getParameter("NETWORK_CONFIG_NATIVE_TOKEN_PRICE_ORACLE_ADDRESS"), - m.getParameter("NETWORK_CONFIG_NATIVE_TOKEN_PRICE_ORACLE_HEARTBEAT"), - m.getParameter("NETWORK_CONFIG_ACCESS_AUTHORITY_ADDRESS"), + oracleMock ? oracleMock : m.getParameter("NETWORK_CONFIG_NATIVE_TOKEN_PRICE_ORACLE_ADDRESS"), + oracleMock ? 1000000000000 : m.getParameter("NETWORK_CONFIG_NATIVE_TOKEN_PRICE_ORACLE_HEARTBEAT"), + process.env.NETWORK_CONFIG_ACCESS_AUTHORITY_ADDRESS ?? m.getParameter("NETWORK_CONFIG_ACCESS_AUTHORITY_ADDRESS"), ]); return { networkConfig }; diff --git a/packages/hardhat/ignition/modules/LocalDevDeploymentModule.ts b/packages/hardhat/ignition/modules/LocalDevDeploymentModule.ts new file mode 100644 index 0000000..7bdc62a --- /dev/null +++ b/packages/hardhat/ignition/modules/LocalDevDeploymentModule.ts @@ -0,0 +1,32 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +import DeployGenericERC20Module from "./Deploy_GenericERC20"; +import FlatPriceSaleFactoryV2Module from "./FlatPriceSaleFactoryV2Module"; +import FlatPriceSaleFactoryV3Module from "./FlatPriceSaleFactoryV3Module"; +import FlatPriceSaleFactoryV4Module from "./FlatPriceSaleFactoryV4Module"; +import InitializeNetworkConfigModule from "./InitializeNetworkConfigModule"; +import SuiteDistributorFactoryV3Module from "./SuiteDistributorFactoryV3Module"; +import SuiteDistributorFactoryV4Module from "./SuiteDistributorFactoryV4Module"; +import SuiteDistributorFactoryV5Module from "./SuiteDistributorFactoryV5Module"; + +export default buildModule("LocalDevDeploymentModule", m => { + const GenericERC20 = m.useModule(DeployGenericERC20Module); + const flatPriceSaleFactoryV2Module = m.useModule(FlatPriceSaleFactoryV2Module); + const flatPriceSaleFactoryV3Module = m.useModule(FlatPriceSaleFactoryV3Module); + const flatPriceSaleFactoryV4Module = m.useModule(FlatPriceSaleFactoryV4Module); + const initializeNetworkConfigModule = m.useModule(InitializeNetworkConfigModule); + const suiteDistributorFactoryV3Module = m.useModule(SuiteDistributorFactoryV3Module); + const suiteDistributorFactoryV4Module = m.useModule(SuiteDistributorFactoryV4Module); + const suiteDistributorFactoryV5Module = m.useModule(SuiteDistributorFactoryV5Module); + + return { + ...GenericERC20, + ...flatPriceSaleFactoryV2Module, + ...flatPriceSaleFactoryV3Module, + ...flatPriceSaleFactoryV4Module, + ...initializeNetworkConfigModule, + ...suiteDistributorFactoryV3Module, + ...suiteDistributorFactoryV4Module, + ...suiteDistributorFactoryV5Module, + }; +}); diff --git a/packages/hardhat/ignition/modules/NetworkConfigModule.ts b/packages/hardhat/ignition/modules/NetworkConfigModule.ts index 05bbe26..e7fbe85 100644 --- a/packages/hardhat/ignition/modules/NetworkConfigModule.ts +++ b/packages/hardhat/ignition/modules/NetworkConfigModule.ts @@ -1,7 +1,7 @@ import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; const networkConfigProxyModule = buildModule("NetworkConfigProxyModule", m => { - const networkConfigProxyAdminOwner = m.getParameter("NETWORK_CONFIG_PROXY_ADMIN"); + const networkConfigProxyAdminOwner = process.env.NETWORK_CONFIG_PROXY_ADMIN ?? m.getParameter("NETWORK_CONFIG_PROXY_ADMIN"); // uninitialized implementation const networkConfig = m.contract("NetworkConfig"); diff --git a/packages/hardhat/ignition/modules/SuiteDistributorFactoryV3Module.ts b/packages/hardhat/ignition/modules/SuiteDistributorFactoryV3Module.ts new file mode 100644 index 0000000..1e14faf --- /dev/null +++ b/packages/hardhat/ignition/modules/SuiteDistributorFactoryV3Module.ts @@ -0,0 +1,21 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +export default buildModule("SuiteDistributorFactoryV3Module", m => { + const continuousVestingMerkleDistributor_v_3_0 = m.contract("ContinuousVestingMerkleDistributor", []); + const trancheVestingMerkleDistributor_v_3_0 = m.contract("TrancheVestingMerkleDistributor", []); + + const continuousVestingMerkleDistributorFactory_v_3_0 = m.contract( + "ContinuousVestingMerkleDistributorFactory", + [continuousVestingMerkleDistributor_v_3_0], + ); + const trancheVestingMerkleDistributorFactory_v_3_0 = m.contract("TrancheVestingMerkleDistributorFactory", [ + trancheVestingMerkleDistributor_v_3_0, + ]); + + return { + continuousVestingMerkleDistributor_v_3_0, + trancheVestingMerkleDistributor_v_3_0, + continuousVestingMerkleDistributorFactory_v_3_0, + trancheVestingMerkleDistributorFactory_v_3_0, + }; +}); diff --git a/packages/subgraph/src/sale/v3.0/flatPriceSaleFactoryMapping.ts b/packages/subgraph/src/sale/v3.0/flatPriceSaleFactoryMapping.ts index 50bc5a3..3b749f7 100644 --- a/packages/subgraph/src/sale/v3.0/flatPriceSaleFactoryMapping.ts +++ b/packages/subgraph/src/sale/v3.0/flatPriceSaleFactoryMapping.ts @@ -1,6 +1,6 @@ import { BigInt } from "@graphprotocol/graph-ts"; -import { NewSale } from "../../../generated/FlatPriceSaleFactory_v_3/FlatPriceSaleFactory_v_3"; +import { NewSale } from "../../../generated/templates/FlatPriceSale_v_3/FlatPriceSaleFactory_v_3"; import { getOrCreateAccount, getOrCreateNativePaymentMethod } from "../../lib"; import {SaleImplementation, Sale} from "../../../generated/schema"; import { FlatPriceSale_v_3 } from '../../../generated/templates' diff --git a/packages/subgraph/src/sale/v3.0/saleImplementationMapping.ts b/packages/subgraph/src/sale/v3.0/saleImplementationMapping.ts index b59c61e..26bccd5 100644 --- a/packages/subgraph/src/sale/v3.0/saleImplementationMapping.ts +++ b/packages/subgraph/src/sale/v3.0/saleImplementationMapping.ts @@ -1,7 +1,7 @@ import { ImplementationConstructor, FlatPriceSale_v_3 as FlatPriceSaleContract -} from "../../../generated/FlatPriceSale_v_3/FlatPriceSale_v_3"; +} from "../../../generated/templates/FlatPriceSale_v_3/FlatPriceSale_v_3"; import { SaleImplementation } from "../../../generated/schema"; diff --git a/packages/subgraph/src/sale/v3.0/saleMapping.ts b/packages/subgraph/src/sale/v3.0/saleMapping.ts index eded596..f5f24bc 100644 --- a/packages/subgraph/src/sale/v3.0/saleMapping.ts +++ b/packages/subgraph/src/sale/v3.0/saleMapping.ts @@ -8,7 +8,7 @@ import { OwnershipTransferred, RegisterDistributor, FlatPriceSale_v_3 as FlatPriceSaleContract -} from "../../../generated/FlatPriceSale_v_3/FlatPriceSale_v_3"; +} from "../../../generated/templates/FlatPriceSale_v_3/FlatPriceSale_v_3"; import { SaleImplementation, diff --git a/packages/subgraph/src/sale/v4.0/saleMapping.ts b/packages/subgraph/src/sale/v4.0/saleMapping.ts index e21d797..0fad0f0 100644 --- a/packages/subgraph/src/sale/v4.0/saleMapping.ts +++ b/packages/subgraph/src/sale/v4.0/saleMapping.ts @@ -8,7 +8,7 @@ import { OwnershipTransferred, RegisterDistributor, FlatPriceSale_v_4_0 as FlatPriceSaleContract -} from "../../../generated/FlatPriceSale_v_4_0/FlatPriceSale_v_4_0"; +} from "../../../generated/templates/FlatPriceSale_v_4_0/FlatPriceSale_v_4_0"; import { SaleImplementation, diff --git a/packages/subgraph/src/subgraph.template.yaml b/packages/subgraph/src/subgraph.template.yaml index d300d55..ff2d8c7 100644 --- a/packages/subgraph/src/subgraph.template.yaml +++ b/packages/subgraph/src/subgraph.template.yaml @@ -514,6 +514,74 @@ dataSources: - event: DistributorDeployed(indexed address) handler: handleDistributorDeployed {{/each}} + {{#each ContinuousVestingMerkleDistributorFactory_v_5_0}} + - kind: ethereum/contract + name: ContinuousVestingMerkleDistributorFactory_v_5_0 + network: {{../SubgraphNetwork}} + source: + address: '{{Address}}' + abi: ContinuousVestingMerkleDistributorFactory + startBlock: {{BlockNumber}} + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + file: ./src/distributor/v3.0/continuousVestingMerkleDistributorFactoryMapping.ts + entities: + - Distributor + - AdvancedDistributor + - ContinuousVesting + abis: + - name: AdvancedDistributor + file: ./abis/contracts/claim/abstract/AdvancedDistributor.sol/AdvancedDistributor.json + - name: ContinuousVestingMerkleDistributorFactory + file: ./abis/contracts/claim/factory/ContinuousVestingMerkleDistributorFactory.sol/ContinuousVestingMerkleDistributorFactory.json + - name: IContinuousVesting + file: ./abis/contracts/interfaces/IContinuousVesting.sol/IContinuousVesting.json + - name: IDistributor + file: ./abis/contracts/interfaces/IDistributor.sol/IDistributor.json + - name: IERC20Metadata + file: ./abis/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol/IERC20Metadata.json + - name: IMerkleSet + file: ./abis/contracts/interfaces/IMerkleSet.sol/IMerkleSet.json + eventHandlers: + - event: DistributorDeployed(indexed address) + handler: handleDistributorDeployed + {{/each}} + {{#each TrancheVestingMerkleDistributorFactory_v_5_0}} + - kind: ethereum/contract + name: TrancheVestingMerkleDistributorFactory_v_5_0 + network: {{../SubgraphNetwork}} + source: + address: '{{Address}}' + abi: TrancheVestingMerkleDistributorFactory + startBlock: {{BlockNumber}} + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + file: ./src/distributor/v3.0/trancheVestingMerkleDistributorFactoryMapping.ts + entities: + - Distributor + - AdvancedDistributor + - TrancheVesting + abis: + - name: AdvancedDistributor + file: ./abis/contracts/claim/abstract/AdvancedDistributor.sol/AdvancedDistributor.json + - name: TrancheVestingMerkleDistributorFactory + file: ./abis/contracts/claim/factory/TrancheVestingMerkleDistributorFactory.sol/TrancheVestingMerkleDistributorFactory.json + - name: ITrancheVesting + file: ./abis/contracts/interfaces/ITrancheVesting.sol/ITrancheVesting.json + - name: IDistributor + file: ./abis/contracts/interfaces/IDistributor.sol/IDistributor.json + - name: IERC20Metadata + file: ./abis/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol/IERC20Metadata.json + - name: IMerkleSet + file: ./abis/contracts/interfaces/IMerkleSet.sol/IMerkleSet.json + eventHandlers: + - event: DistributorDeployed(indexed address) + handler: handleDistributorDeployed + {{/each}} {{#TrancheVestingMerkleDistributorFactory.[0]}} - kind: ethereum/contract name: TrancheVestingMerkleDistributorFactory @@ -892,4 +960,4 @@ templates: - event: SweepNative(uint256) handler: handleSweepNative - event: RegisterDistributor(address) - handler: handleRegisterDistributor \ No newline at end of file + handler: handleRegisterDistributor