diff --git a/.github/workflows/core-smart-contract-ci.yml b/.github/workflows/core-smart-contract-ci.yml new file mode 100644 index 000000000..0f10de06b --- /dev/null +++ b/.github/workflows/core-smart-contract-ci.yml @@ -0,0 +1,72 @@ +name: Core Smart Contract - Default + +on: + pull_request: + branches: + - '*' + paths: + - 'packages/smart-contract/**' + workflow_call: + inputs: + node-version: + description: Node.js version to use + required: false + type: number + default: 20 + +concurrency: + group: ${{ github.ref }}-core-smart-contract-ci + cancel-in-progress: true + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node-version }} + cache: 'npm' + cache-dependency-path: 'packages/smart-contract' + + - name: Install dependencies + working-directory: packages/smart-contract + run: npm ci + + - name: Check Format + working-directory: packages/smart-contract + run: npm run check-format + + - name: Check Lint + working-directory: packages/smart-contract + run: npm run lint + + - name: Compile smart contracts + working-directory: packages/smart-contract + run: npm run compile + + - name: Run Coverage + working-directory: packages/smart-contract + run: npm run coverage + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: iExecBlockchainComputing/dataprotector-sdk + + - name: Run static analysis with slither + uses: crytic/slither-action@v0.4.1 + with: + target: "packages/smart-contract/" + slither-args: --checklist --markdown-root ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/ + fail-on: none # TODO set this to high or other + sarif: results.sarif + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif diff --git a/.github/workflows/core-smart-contract-deploy.yml b/.github/workflows/core-smart-contract-deploy.yml new file mode 100644 index 000000000..81591a205 --- /dev/null +++ b/.github/workflows/core-smart-contract-deploy.yml @@ -0,0 +1,106 @@ +name: Smart Contract Deploy + +on: + workflow_dispatch: # Manual trigger + inputs: + network: + description: 'Network' + required: true + type: choice + options: + - hardhat + - avalancheFujiTestnet + - arbitrumSepolia + - arbitrum + - bellecour + default: 'hardhat' + environment: + description: 'Environment' + required: true + type: choice + options: + - dev + - prod + default: 'dev' + + +jobs: + build-and-test: + uses: ./.github/workflows/core-smart-contract-ci.yml + with: + node-version: 20 + + deploy: + needs: build-and-test + runs-on: ubuntu-latest + env: + CI: true + permissions: + contents: write # Required to commit deployment files. + environment: ${{ inputs.network }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + cache-dependency-path: 'packages/smart-contract' + + - name: Install dependencies + working-directory: packages/smart-contract + run: npm ci + + - name: Validate deployment environment and prepare variables + if: inputs.network != 'hardhat' + run: | + NETWORK="${{ inputs.network }}" + ENVIRONMENT="${{ inputs.environment }}" + + case "$NETWORK" in + arbitrum|bellecour) + if [ "$ENVIRONMENT" = "dev" ]; then + echo "Error: Cannot deploy to mainnet ($NETWORK) with dev environment" + exit 1 + fi + echo "IS_MAINNET=true" >> $GITHUB_ENV + ;; + *) + echo "IS_MAINNET=false" >> $GITHUB_ENV + ;; + esac + + - name: Deploy contract + working-directory: packages/smart-contract + env: + # For Deployment + RPC_URL: ${{ secrets.RPC_URL }} + DEPLOYER_PRIVATE_KEY: ${{ secrets.DEPLOYER_PRIVATE_KEY }} + DATASET_REGISTRY_ADDRESS: ${{ vars.DATASET_REGISTRY_ADDRESS }} + # For Verification + EXPLORER_API_KEY: ${{ secrets.EXPLORER_API_KEY }} + IS_VERIFICATION_API_V2: ${{ vars.IS_VERIFICATION_API_V2 }} + run: | + if [ "${{ inputs.network }}" = "hardhat" ]; then + npm run deploy -- --network ${{ inputs.network }} + else + # For testnets, use network-environment; for mainnets, use network only + if [ "$IS_MAINNET" = false ]; then + DEPLOYMENT_ID="${{ inputs.network }}-${{ inputs.environment }}" + else + DEPLOYMENT_ID="${{ inputs.network }}" + fi + npm run deploy -- --network ${{ inputs.network }} --deployment-id "$DEPLOYMENT_ID" --verify + fi + + - name: Save deployment artifacts + if: inputs.network != 'hardhat' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: 'chore: save deployment artifacts for ${{ inputs.network }} ${{ inputs.environment }} (${{ github.run_id }})' + file_pattern: 'packages/smart-contract/ignition/deployments/*' + commit_user_name: 'GitHub Actions Bot' + commit_user_email: 'github-actions[bot]@users.noreply.github.com' + commit_author: 'GitHub Actions Bot ' diff --git a/.github/workflows/deploy-smart-contract.yml b/.github/workflows/deploy-smart-contract.yml deleted file mode 100644 index 52f074df3..000000000 --- a/.github/workflows/deploy-smart-contract.yml +++ /dev/null @@ -1,96 +0,0 @@ -name: Smart Contract Deploy - -on: - workflow_dispatch: # Manually trigger the workflow OR trigger with tags or releases ? - inputs: - target: - description: 'Deployment target (smart-contract-deploy-dev, smart-contract-deploy-staging, smart-contract-deploy-prod)' - required: true - type: choice - options: - - smart-contract-deploy-dev - - smart-contract-deploy-staging - - smart-contract-deploy-prod - default: smart-contract-deploy-dev - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: '18' - - - name: Install dependencies - working-directory: packages/smart-contract - run: | - node -v - npm -v - npm ci - - - name: Check code format - working-directory: packages/smart-contract - run: npm run check-format - - - name: Run lint - working-directory: packages/smart-contract - run: npm run lint - - - name: Compile smart contracts - working-directory: packages/smart-contract - run: npm run compile - - - name: Run tests - working-directory: packages/smart-contract - run: npm run test - - - name: Deploy to dev/staging - if: ${{ (github.event.inputs.target == 'smart-contract-deploy-dev' || github.event.inputs.target == 'smart-contract-deploy-staging') && startsWith(github.ref, 'refs/heads/main') }} - working-directory: packages/smart-contract - env: - WALLET_PRIVATE_KEY: ${{ secrets.DEPLOYER_DEV_PRIVATEKEY }} - run: npm run deploy -- --network bellecour - - - name: Deploy to prod - if: ${{ github.event.inputs.target == 'smart-contract-deploy-prod' && github.ref == 'refs/heads/main' }} - working-directory: packages/smart-contract - env: - WALLET_PRIVATE_KEY: ${{ secrets.DEPLOYER_PROD_PRIVATEKEY }} - run: npm run deploy -- --network bellecour - - - name: Update production environment - if: ${{ github.event.inputs.target == 'smart-contract-deploy-prod' }} - working-directory: environments - run: | - ADDRESS=$(jq -r '.contractAddress' ../packages/smart-contract/ignition/deployments/chain-134/journal.jsonl) - BLOCK=$(jq -r '.blockNumber' ../packages/smart-contract/ignition/deployments/chain-134/journal.jsonl) - KEY=dataprotectorContractAddress VALUE=$ADDRESS npm run update-env - KEY=dataprotectorStartBlock VALUE=$BLOCK npm run update-env - git add environments.json - git commit -m "Deployment ${{ github.event.inputs.target }} run ${{ github.run_number }} commit ${{ github.sha }}" --author="drone-product " - - - name: Update staging environment - if: ${{ github.event.inputs.target == 'smart-contract-deploy-staging' }} - working-directory: environments - run: | - ADDRESS=$(jq -r '.contractAddress' ../packages/smart-contract/ignition/deployments/chain-134/journal.json) - BLOCK=$(jq -r '.blockNumber' ../packages/smart-contract/ignition/deployments/chain-134/journal.json) - KEY=dataprotectorContractAddress VALUE=$ADDRESS npm run update-env - KEY=dataprotectorStartBlock VALUE=$BLOCK npm run update-env - git add environments.json - git commit -m "Deployment ${{ github.event.inputs.target }} run ${{ github.run_number }} commit ${{ github.sha }}" --author="drone-product " - - - name: Git push environment update - if: ${{ github.event.inputs.target == 'smart-contract-deploy-prod' || github.event.inputs.target == 'smart-contract-deploy-staging' }} - run: | - git push ssh://git@github.com/iExecBlockchainComputing/dataprotector-sdk.git update-env-${{ github.run_number }} - env: - # Configure the SSH key to secrets GitHub - SSH_KEY: ${{ secrets.SSH_KEY_TEAM_PRODUCT_GITHUB_PUSH }} - shell: bash - - - name: Verify contract - working-directory: packages/smart-contract - run: npm run verify -- --network bellecour $(cat deployments/DataProtector/address) $(cat deployments/DataProtector/args) diff --git a/packages/smart-contract/.env.template b/packages/smart-contract/.env.template index 545ad5de0..4c78b3ff7 100644 --- a/packages/smart-contract/.env.template +++ b/packages/smart-contract/.env.template @@ -1,5 +1,5 @@ # wallet used for transactions -WALLET_PRIVATE_KEY= +DEPLOYER_PRIVATE_KEY= # DatasetRegistry contract address override (deploy script only) DATASET_REGISTRY_ADDRESS= @@ -10,5 +10,8 @@ RPC_URL= ## Mnemonic for the network MNEMONIC= -## Arbiscan API key to verify contracts -ARBISCAN_API_KEY= +## API key to verify contracts +EXPLORER_API_KEY= + +## Whether to use API V2 verification format +IS_VERIFICATION_API_V2= diff --git a/packages/smart-contract/.nvmrc b/packages/smart-contract/.nvmrc new file mode 100644 index 000000000..209e3ef4b --- /dev/null +++ b/packages/smart-contract/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/packages/smart-contract/CHANGELOG.md b/packages/smart-contract/CHANGELOG.md index 491e98087..23ff5a3e6 100644 --- a/packages/smart-contract/CHANGELOG.md +++ b/packages/smart-contract/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Added +- Fix CIs and Support for Arbitrum mainnet (#468) - Support for Arbitrum and Avalanche Fuji testnets (#429). ### Changed diff --git a/packages/smart-contract/config/env.ts b/packages/smart-contract/config/env.ts index 0e36d86af..9e263e733 100644 --- a/packages/smart-contract/config/env.ts +++ b/packages/smart-contract/config/env.ts @@ -6,7 +6,7 @@ const privateKeyRegex = /(^|\b)(0x)?[0-9a-fA-F]{64}(\b|$)/; const envSchema = z.object({ // Private key of the wallet used for transactions - WALLET_PRIVATE_KEY: z + DEPLOYER_PRIVATE_KEY: z .string() .regex(privateKeyRegex, 'Invalid private key format') .optional() @@ -26,7 +26,17 @@ const envSchema = z.object({ MNEMONIC: z.string().min(1, 'MNEMONIC cannot be empty').optional().or(z.literal('')), // Arbiscan API key - ARBISCAN_API_KEY: z.string().optional().or(z.literal('')), + EXPLORER_API_KEY: z.string().optional().or(z.literal('')), + + // Whether to use API V2 verification format + IS_VERIFICATION_API_V2: z + .string() + .optional() + .default('true') + .refine((val) => val === 'true' || val === 'false', { + message: 'IS_VERIFICATION_API_V2 must be "true" or "false"', + }) + .transform((val) => val === 'true'), }); export const env = envSchema.parse(process.env); diff --git a/packages/smart-contract/hardhat.config.ts b/packages/smart-contract/hardhat.config.ts index 96b5a20be..1149765bb 100644 --- a/packages/smart-contract/hardhat.config.ts +++ b/packages/smart-contract/hardhat.config.ts @@ -2,19 +2,7 @@ import '@nomicfoundation/hardhat-toolbox'; import { HardhatUserConfig } from 'hardhat/config'; import { env } from './config/env'; -const privateKey = env.WALLET_PRIVATE_KEY; - -// Avalanche Fuji specific configuration -const fujiBaseConfig = { - blockGasLimit: 8_000_000, - chainId: 43113, -}; - -// Arbitrum Sepolia specific configuration -const arbitrumSepoliaBaseConfig = { - blockGasLimit: 30_000_000, // Arbitrum has higher block gas limits - chainId: 421614, -}; +const privateKey = env.DEPLOYER_PRIVATE_KEY; const config: HardhatUserConfig = { networks: { @@ -34,13 +22,21 @@ const config: HardhatUserConfig = { avalancheFuji: { url: env.RPC_URL || 'https://api.avax-test.network/ext/bc/C/rpc', accounts: privateKey ? [privateKey] : [], - ...fujiBaseConfig, + blockGasLimit: 8_000_000, + chainId: 43113, }, // Add Arbitrum Sepolia as a network arbitrumSepolia: { url: env.RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc', accounts: privateKey ? [privateKey] : [], - ...arbitrumSepoliaBaseConfig, + blockGasLimit: 30_000_000, // Arbitrum has higher block gas limits + chainId: 421614, + }, + arbitrum: { + url: env.RPC_URL || 'https://arb1.arbitrum.io/rpc', + accounts: privateKey ? [privateKey] : [], + blockGasLimit: 30_000_000, // Arbitrum has higher block gas limits + chainId: 42161, }, // poco-chain native config 'dev-native': { @@ -54,11 +50,12 @@ const config: HardhatUserConfig = { }, //to verify contract on Blockscout etherscan: { - apiKey: { - bellecour: 'nothing', // a non-empty string is needed by the plugin. - avalancheFuji: 'nothing', // a non-empty string is needed by the plugin. - arbitrumSepolia: env.ARBISCAN_API_KEY || '', - }, + apiKey: env.IS_VERIFICATION_API_V2 + ? env.EXPLORER_API_KEY + : { + bellecour: env.EXPLORER_API_KEY || 'nothing', // a non-empty string is needed by the plugin. + avalancheFuji: env.EXPLORER_API_KEY || 'nothing', // a non-empty string is needed by the plugin. + }, customChains: [ { network: 'bellecour', diff --git a/packages/smart-contract/package.json b/packages/smart-contract/package.json index d9ddfde6e..22ffec29c 100644 --- a/packages/smart-contract/package.json +++ b/packages/smart-contract/package.json @@ -3,8 +3,9 @@ "version": "0.1.0", "scripts": { "compile": "hardhat compile && npm run artifact-to-abis", - "deploy": "hardhat ignition deploy ignition/modules/DataProtector.ts --strategy create2", "test": "hardhat test", + "coverage": "hardhat coverage", + "deploy": "hardhat ignition deploy ignition/modules/DataProtector.ts --strategy create2", "artifact-to-abis": "node tools/artifacts-to-abis.mjs", "check-format": "prettier --loglevel warn 'contracts/**/*.sol' '**/*.ts' --check", "format": "prettier --loglevel warn 'contracts/**/*.sol' '**/*.ts' --write",