diff --git a/.gitignore b/.gitignore index 19d4ba3613..e767737c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,7 @@ tsconfig.build.tsbuildinfo /packages/smart-contracts/.slither-cache/ /packages/smart-contracts/crytic-export/ -.nx-cache/ \ No newline at end of file +.nx-cache/ + +# A place to store AI-generated or temporary files +.ignore/ diff --git a/BASE_SEPOLIA_README.md b/BASE_SEPOLIA_README.md deleted file mode 100644 index 081e0beeb7..0000000000 --- a/BASE_SEPOLIA_README.md +++ /dev/null @@ -1,198 +0,0 @@ -# Base Sepolia Support for Request Network - -This directory contains all the changes needed to deploy and use ERC20FeeProxy and ERC20CommerceEscrowWrapper contracts on Base Sepolia testnet. - -## Quick Start - -### 1. Set up your environment - -```bash -# Set your private key (without 0x prefix) -export DEPLOYMENT_PRIVATE_KEY=your_private_key_here - -# Get Base Sepolia ETH from faucet -# https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet -``` - -### 2. Deploy contracts - -```bash -cd packages/smart-contracts - -# Build contracts -yarn build:sol - -# Deploy using helper script -./scripts/deploy-base-sepolia.sh - -# OR deploy directly -yarn hardhat deploy-erc20-commerce-escrow-wrapper --network base-sepolia -``` - -### 3. Update deployed addresses - -After deployment, update the contract addresses in: - -- `packages/smart-contracts/src/lib/artifacts/ERC20FeeProxy/index.ts` -- `packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts` - -### 4. Rebuild packages - -```bash -cd packages/smart-contracts -yarn build -``` - -## Network Details - -| Property | Value | -| ------------ | ----------------------------- | -| Network Name | Base Sepolia | -| Chain ID | 84532 | -| RPC URL | https://sepolia.base.org | -| Explorer | https://sepolia.basescan.org/ | -| Type | Testnet | - -## Deployed Contracts - -### Official Coinbase Contracts - -- **AuthCaptureEscrow**: `0xBdEA0D1bcC5966192B070Fdf62aB4EF5b4420cff` - -### Request Network Contracts (to be deployed) - -- **ERC20FeeProxy**: Pending deployment -- **ERC20CommerceEscrowWrapper**: Pending deployment - -## Supported Tokens - -| Token | Address | Decimals | -| ----- | -------------------------------------------- | -------- | -| USDC | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | 6 | - -## SDK Usage Example - -```typescript -import { RequestNetwork, Types } from '@requestnetwork/request-client.js'; - -const requestNetwork = new RequestNetwork({ - nodeConnectionConfig: { - baseURL: 'https://sepolia.gateway.request.network/', - }, -}); - -// Create a request on Base Sepolia -const request = await requestNetwork.createRequest({ - requestInfo: { - currency: { - type: Types.RequestLogic.CURRENCY.ERC20, - value: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC - network: 'base-sepolia', - }, - expectedAmount: '1000000', // 1 USDC - payee: { - type: Types.Identity.TYPE.ETHEREUM_ADDRESS, - value: '0xPayeeAddress', - }, - }, - paymentNetwork: { - id: Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT, - parameters: { - paymentNetworkName: 'base-sepolia', - paymentAddress: '0xPayeeAddress', - }, - }, - signer: yourSigner, -}); -``` - -## Files Changed - -### Type System - -- ✅ `packages/types/src/currency-types.ts` - Added `'base-sepolia'` to EvmChainName - -### Currency Package - -- ✅ `packages/currency/src/chains/evm/data/base-sepolia.ts` - New chain definition -- ✅ `packages/currency/src/erc20/chains/base-sepolia.ts` - New token list -- ✅ `packages/currency/src/chains/evm/index.ts` - Export chain -- ✅ `packages/currency/src/erc20/chains/index.ts` - Export tokens - -### Smart Contracts - -- ✅ `packages/smart-contracts/src/lib/artifacts/ERC20FeeProxy/index.ts` - Added deployment config -- ✅ `packages/smart-contracts/src/lib/artifacts/AuthCaptureEscrow/index.ts` - Added official address -- ✅ `packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts` - Added deployment config -- ✅ `packages/smart-contracts/hardhat.config.ts` - Already configured ✓ - -### Payment Detection - -- ✅ `packages/payment-detection/src/eth/multichainExplorerApiProvider.ts` - Added network - -## Documentation Files - -- 📖 **BASE_SEPOLIA_DEPLOYMENT_GUIDE.md** - Complete deployment guide -- 📖 **BASE_SEPOLIA_CHANGES_SUMMARY.md** - Detailed list of all changes -- 📖 **BASE_SEPOLIA_README.md** - This file (quick reference) - -## Helper Scripts - -- 🛠️ **packages/smart-contracts/scripts/deploy-base-sepolia.sh** - Interactive deployment script -- 🛠️ **packages/smart-contracts/scripts/deploy-erc20-commerce-escrow-wrapper.ts** - Core deployment logic -- 🛠️ **packages/smart-contracts/scripts/test-base-sepolia-deployment.ts** - Test connection script - -## Testing Checklist - -- [ ] Fund deployment wallet with Base Sepolia ETH -- [ ] Deploy ERC20FeeProxy to Base Sepolia -- [ ] Deploy ERC20CommerceEscrowWrapper to Base Sepolia -- [ ] Update artifact files with deployed addresses -- [ ] Rebuild all packages -- [ ] Create a test request using Base Sepolia USDC -- [ ] Pay the test request -- [ ] Verify payment is detected correctly -- [ ] Test commerce escrow flow - -## Troubleshooting - -### Insufficient funds - -Get Base Sepolia ETH from: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet - -### RPC connection issues - -Try alternative RPC: `https://base-sepolia-rpc.publicnode.com` - -### Contract verification failed - -Manually verify on Basescan: - -```bash -yarn hardhat verify --network base-sepolia -``` - -### Linting errors - -Run linter: - -```bash -yarn lint -``` - -## Resources - -- [Base Documentation](https://docs.base.org/) -- [Request Network Documentation](https://docs.request.network/) -- [Coinbase Commerce Payments](https://github.com/base/commerce-payments) -- [Base Sepolia Faucet](https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet) -- [Base Sepolia Explorer](https://sepolia.basescan.org/) - -## Support - -- Request Network Discord: https://discord.gg/requestnetwork -- GitHub Issues: https://github.com/RequestNetwork/requestNetwork/issues - -## License - -MIT diff --git a/packages/payment-detection/codegen.yml b/packages/payment-detection/codegen.yml index 9b5155366d..f67dfd4365 100644 --- a/packages/payment-detection/codegen.yml +++ b/packages/payment-detection/codegen.yml @@ -1,5 +1,5 @@ overwrite: true -schema: 'https://subgraph.satsuma-prod.com/e2e4905ab7c8/request-network--434873/request-payments-sepolia/api' +schema: 'https://api.studio.thegraph.com/query/67444/request-payments-sepolia/version/latest' documents: src/thegraph/queries/*.graphql generates: src/thegraph/generated/graphql.ts: diff --git a/packages/payment-detection/src/thegraph/client.ts b/packages/payment-detection/src/thegraph/client.ts index 27acbb72a9..f5700ae013 100644 --- a/packages/payment-detection/src/thegraph/client.ts +++ b/packages/payment-detection/src/thegraph/client.ts @@ -11,9 +11,6 @@ const THE_GRAPH_STUDIO_URL = const THE_GRAPH_EXPLORER_URL = 'https://gateway.thegraph.com/api/$API_KEY/subgraphs/id/$SUBGRAPH_ID'; -const THE_GRAPH_ALCHEMY_URL = - 'https://subgraph.satsuma-prod.com/e2e4905ab7c8/request-network--434873/request-payments-$NETWORK/api'; - const THE_GRAPH_URL_MANTLE_TESTNET = 'https://graph.testnet.mantle.xyz/subgraphs/name/requestnetwork/request-payments-mantle-testnet'; @@ -23,19 +20,6 @@ const THE_GRAPH_URL_MANTLE = const THE_GRAPH_URL_CORE = 'https://thegraph.coredao.org/subgraphs/name/requestnetwork/request-payments-core'; -const THE_GRAPH_ALCHEMY_CHAINS: CurrencyTypes.ChainName[] = [ - 'arbitrum-one', - 'avalanche', - 'base', - 'bsc', - 'fantom', - 'mainnet', - 'matic', - 'sepolia', - 'optimism', - 'zksyncera', -]; - const THE_GRAPH_EXPLORER_SUBGRAPH_ID: Partial> = { ['arbitrum-one']: '3MtDdHbzvBVNBpzUTYXGuDDLgTd1b8bPYwoH1Hdssgp9', avalanche: 'A27V4PeZdKHeyuBkehdBJN8cxNtzVpXvYoqkjHUHRCFp', @@ -159,10 +143,8 @@ export const getTheGraphClientUrl = ( '$API_KEY', theGraphExplorerApiKey || '', ).replace('$SUBGRAPH_ID', theGraphExplorerSubgraphId || ''); - const theGraphAlchemyUrl = THE_GRAPH_ALCHEMY_URL.replace('$NETWORK', chain); const shouldUseTheGraphExplorer = !!theGraphExplorerApiKey && !!theGraphExplorerSubgraphId; - const shouldUseAlchemy = THE_GRAPH_ALCHEMY_CHAINS.includes(chain); switch (true) { case chain === 'private': @@ -174,10 +156,6 @@ export const getTheGraphClientUrl = ( case chain === 'core': return THE_GRAPH_URL_CORE; default: - return shouldUseTheGraphExplorer - ? theGraphExplorerUrl - : shouldUseAlchemy - ? theGraphAlchemyUrl - : theGraphStudioUrl; + return shouldUseTheGraphExplorer ? theGraphExplorerUrl : theGraphStudioUrl; } }; diff --git a/packages/payment-detection/test/thegraph/client.test.ts b/packages/payment-detection/test/thegraph/client.test.ts index d8cccc4d76..643d75a393 100644 --- a/packages/payment-detection/test/thegraph/client.test.ts +++ b/packages/payment-detection/test/thegraph/client.test.ts @@ -5,10 +5,10 @@ describe('getTheGraphClientUrl', () => { const url = getTheGraphClientUrl('base', { url: 'test' }); expect(url).toBe('test'); }); - it('should build the correct URL for network supported by Alchemy', () => { + it('should build the correct URL for network using TheGraph Studio', () => { const url = getTheGraphClientUrl('base'); expect(url).toBe( - 'https://subgraph.satsuma-prod.com/e2e4905ab7c8/request-network--434873/request-payments-base/api', + 'https://api.studio.thegraph.com/query/67444/request-payments-base/version/latest', ); }); it('should build the correct URL when using TheGraph Explorer API key', () => { diff --git a/packages/payment-processor/test/payment/erc20-commerce-escrow-wrapper.test.ts b/packages/payment-processor/test/payment/erc20-commerce-escrow-wrapper.test.ts index 36132915cd..841f445a26 100644 --- a/packages/payment-processor/test/payment/erc20-commerce-escrow-wrapper.test.ts +++ b/packages/payment-processor/test/payment/erc20-commerce-escrow-wrapper.test.ts @@ -32,6 +32,9 @@ const wallet = Wallet.fromMnemonic(mnemonic).connect(provider); const network: CurrencyTypes.EvmChainName = 'sepolia'; const erc20ContractAddress = '0x9FBDa871d559710256a2502A2517b794B482Db40'; +// Get the real wrapper address from the deployed contract +const wrapperAddress = getCommerceEscrowWrapperAddress(network); + const mockAuthorizeParams: AuthorizePaymentParams = { paymentReference: '0x0123456789abcdef', payer: wallet.address, @@ -75,7 +78,9 @@ describe('erc20-commerce-escrow-wrapper', () => { describe('getCommerceEscrowWrapperAddress', () => { it('should return address when wrapper is deployed on testnet', () => { const address = getCommerceEscrowWrapperAddress(network); - expect(address).toBe('0x1234567890123456789012345678901234567890'); + // Verify it returns a valid Ethereum address + expect(address).toMatch(/^0x[0-9a-fA-F]{40}$/); + expect(address).not.toBe('0x0000000000000000000000000000000000000000'); }); it('should throw when wrapper not found on mainnet', () => { @@ -91,19 +96,12 @@ describe('erc20-commerce-escrow-wrapper', () => { }).toThrow('No deployment for network: unsupported-network.'); }); - it('should return different addresses for different supported networks', () => { + it('should return a valid address for sepolia network', () => { const sepoliaAddress = getCommerceEscrowWrapperAddress('sepolia'); - const goerliAddress = getCommerceEscrowWrapperAddress('goerli'); - const mumbaiAddress = getCommerceEscrowWrapperAddress('mumbai'); - - // Verify all addresses are valid hex-formatted addresses - [sepoliaAddress, goerliAddress, mumbaiAddress].forEach((addr) => { - expect(addr).toMatch(/^0x[0-9a-fA-F]{40}$/); - expect(addr).not.toBe('0x0000000000000000000000000000000000000000'); - }); - // Verify all addresses are different - expect(new Set([sepoliaAddress, goerliAddress, mumbaiAddress]).size).toBe(3); + // Verify the address is valid hex-formatted address + expect(sepoliaAddress).toMatch(/^0x[0-9a-fA-F]{40}$/); + expect(sepoliaAddress).not.toBe('0x0000000000000000000000000000000000000000'); }); }); @@ -226,7 +224,7 @@ describe('erc20-commerce-escrow-wrapper', () => { expect(result).toBe('1000000000000000000'); expect(mockGetErc20Allowance).toHaveBeenCalledWith( wallet.address, - '0x1234567890123456789012345678901234567890', // wrapper address + wrapperAddress, // real wrapper address from deployment provider, erc20ContractAddress, ); @@ -631,7 +629,7 @@ describe('erc20-commerce-escrow-wrapper', () => { }); expect(wallet.sendTransaction).toHaveBeenCalledWith({ - to: '0x1234567890123456789012345678901234567890', + to: wrapperAddress, data: expect.stringMatching(/^0x[a-fA-F0-9]+$/), value: 0, }); @@ -648,7 +646,7 @@ describe('erc20-commerce-escrow-wrapper', () => { }); expect(wallet.sendTransaction).toHaveBeenCalledWith({ - to: '0x1234567890123456789012345678901234567890', + to: wrapperAddress, data: expect.stringMatching(/^0x[a-fA-F0-9]+$/), value: 0, }); @@ -665,7 +663,7 @@ describe('erc20-commerce-escrow-wrapper', () => { }); expect(wallet.sendTransaction).toHaveBeenCalledWith({ - to: '0x1234567890123456789012345678901234567890', + to: wrapperAddress, data: expect.stringMatching(/^0x[a-fA-F0-9]+$/), value: 0, }); @@ -682,7 +680,7 @@ describe('erc20-commerce-escrow-wrapper', () => { }); expect(wallet.sendTransaction).toHaveBeenCalledWith({ - to: '0x1234567890123456789012345678901234567890', + to: wrapperAddress, data: expect.stringMatching(/^0x[a-fA-F0-9]+$/), value: 0, }); @@ -699,7 +697,7 @@ describe('erc20-commerce-escrow-wrapper', () => { }); expect(wallet.sendTransaction).toHaveBeenCalledWith({ - to: '0x1234567890123456789012345678901234567890', + to: wrapperAddress, data: expect.stringMatching(/^0x[a-fA-F0-9]+$/), value: 0, }); @@ -716,7 +714,7 @@ describe('erc20-commerce-escrow-wrapper', () => { }); expect(wallet.sendTransaction).toHaveBeenCalledWith({ - to: '0x1234567890123456789012345678901234567890', + to: wrapperAddress, data: expect.stringMatching(/^0x[a-fA-F0-9]+$/), value: 0, }); diff --git a/packages/request-client.js/test/index.test.ts b/packages/request-client.js/test/index.test.ts index be46a27efb..528d4ed308 100644 --- a/packages/request-client.js/test/index.test.ts +++ b/packages/request-client.js/test/index.test.ts @@ -168,6 +168,8 @@ const waitForConfirmation = async ( /* eslint-disable @typescript-eslint/no-unused-expressions */ describe('request-client.js', () => { afterEach(() => { + jest.useRealTimers(); + jest.restoreAllMocks(); jest.resetAllMocks(); }); @@ -204,10 +206,12 @@ describe('request-client.js', () => { mockServer.listen({ onUnhandledRequest: 'bypass' }); }); beforeEach(() => { + mockServer.resetHandlers(); spyPersistTransaction.mockReturnValue({}); spyGetTransactionsByChannelId.mockReturnValue({ result: mockedTransactions }); }); afterAll(() => { + mockServer.resetHandlers(); mockServer.close(); }); @@ -354,6 +358,7 @@ describe('request-client.js', () => { mockServer.close(); }); beforeEach(() => { + mockServer.resetHandlers(); hits = { get: 0, post: 0 }; }); it('allows to create a request', async () => { @@ -1156,6 +1161,7 @@ describe('request-client.js', () => { describe('ETH requests', () => { beforeEach(() => { + jest.useRealTimers(); jest.clearAllMocks(); jest.restoreAllMocks(); }); @@ -1281,16 +1287,17 @@ describe('request-client.js', () => { // This test checks that 2 payments with reference `c19da4923539c37f` have reached 0xc12F17Da12cd01a9CDBB216949BA0b41A6Ffc4EB it('can get the balance of an ETH request', async () => { const etherscanMock = new EtherscanProviderMock(); - ethers.providers.EtherscanProvider.prototype.getHistory = jest - .fn() - .mockImplementation(etherscanMock.getHistory); - ethers.providers.EtherscanProvider.prototype.getNetwork = jest - .fn() - .mockImplementation(etherscanMock.getNetwork); + jest + .spyOn(ethers.providers.EtherscanProvider.prototype, 'getHistory') + .mockImplementation(etherscanMock.getHistory.bind(etherscanMock)); + jest + .spyOn(ethers.providers.EtherscanProvider.prototype, 'getNetwork') + .mockImplementation(etherscanMock.getNetwork.bind(etherscanMock)); const requestNetwork = new RequestNetwork({ signatureProvider: TestData.fakeSignatureProvider, useMockStorage: true, + paymentOptions: { getSubgraphClient: () => undefined }, }); const paymentNetwork: PaymentTypes.PaymentNetworkCreateParameters = { @@ -1311,12 +1318,13 @@ describe('request-client.js', () => { }); const request = await requestNetwork.createRequest({ + disablePaymentDetection: true, paymentNetwork, requestInfo, signer: TestData.payee.identity, }); - await request.waitForConfirmation(); + await new Promise((resolve): any => setTimeout(resolve, 150)); const data = await request.refresh(); // Payment reference should be fixed @@ -1328,6 +1336,8 @@ describe('request-client.js', () => { ), ).toBe('efce79375b2db9f7'); + request.enablePaymentDetection(); + await new Promise((resolve): any => setTimeout(resolve, 150)); const dataAfterRefresh = await request.refresh(); expect(dataAfterRefresh.balance?.balance).toBe('12300000000'); @@ -1341,19 +1351,18 @@ describe('request-client.js', () => { }); it('can disable and enable the get the balance of a request', async () => { - jest.useFakeTimers(); - const etherscanMock = new EtherscanProviderMock(); - ethers.providers.EtherscanProvider.prototype.getHistory = jest - .fn() - .mockImplementation(etherscanMock.getHistory); - ethers.providers.EtherscanProvider.prototype.getNetwork = jest - .fn() - .mockImplementation(etherscanMock.getNetwork); + jest + .spyOn(ethers.providers.EtherscanProvider.prototype, 'getHistory') + .mockImplementation(etherscanMock.getHistory.bind(etherscanMock)); + jest + .spyOn(ethers.providers.EtherscanProvider.prototype, 'getNetwork') + .mockImplementation(etherscanMock.getNetwork.bind(etherscanMock)); const requestNetwork = new RequestNetwork({ signatureProvider: TestData.fakeSignatureProvider, useMockStorage: true, + paymentOptions: { getSubgraphClient: () => undefined }, }); const paymentNetwork: PaymentTypes.PaymentNetworkCreateParameters = { @@ -1380,7 +1389,7 @@ describe('request-client.js', () => { signer: TestData.payee.identity, }); - jest.advanceTimersByTime(150); + await new Promise((resolve): any => setTimeout(resolve, 150)); const data = await request.refresh(); // Payment reference should be fixed @@ -1392,12 +1401,12 @@ describe('request-client.js', () => { ), ).toBe('efce79375b2db9f7'); - jest.advanceTimersByTime(150); + await new Promise((resolve): any => setTimeout(resolve, 150)); let dataAfterRefresh = await request.refresh(); expect(dataAfterRefresh.balance).toBeNull(); request.enablePaymentDetection(); - jest.advanceTimersByTime(150); + await new Promise((resolve): any => setTimeout(resolve, 150)); dataAfterRefresh = await request.refresh(); expect(dataAfterRefresh.balance?.balance).toBe('12300000000'); @@ -1410,7 +1419,7 @@ describe('request-client.js', () => { ); request.disablePaymentDetection(); - jest.advanceTimersByTime(150); + await new Promise((resolve): any => setTimeout(resolve, 150)); dataAfterRefresh = await request.refresh(); expect(dataAfterRefresh.balance?.balance).toBe('12300000000'); @@ -1421,23 +1430,21 @@ describe('request-client.js', () => { expect(dataAfterRefresh.balance?.events[0].parameters!.txHash).toBe( '0x06d95c3889dcd974106e82fa27358549d9392d6fee6ea14fe1acedadc1013114', ); - jest.useRealTimers(); - }); + }, 60000); it('can get the balance on a skipped payment detection request', async () => { - jest.useFakeTimers(); - const etherscanMock = new EtherscanProviderMock(); - ethers.providers.EtherscanProvider.prototype.getHistory = jest - .fn() - .mockImplementation(etherscanMock.getHistory); - ethers.providers.EtherscanProvider.prototype.getNetwork = jest - .fn() - .mockImplementation(etherscanMock.getNetwork); + jest + .spyOn(ethers.providers.EtherscanProvider.prototype, 'getHistory') + .mockImplementation(etherscanMock.getHistory.bind(etherscanMock)); + jest + .spyOn(ethers.providers.EtherscanProvider.prototype, 'getNetwork') + .mockImplementation(etherscanMock.getNetwork.bind(etherscanMock)); const requestNetwork = new RequestNetwork({ signatureProvider: TestData.fakeSignatureProvider, useMockStorage: true, + paymentOptions: { getSubgraphClient: () => undefined }, }); const paymentNetwork: PaymentTypes.PaymentNetworkCreateParameters = { @@ -1464,7 +1471,7 @@ describe('request-client.js', () => { signer: TestData.payee.identity, }); - jest.advanceTimersByTime(150); + await new Promise((resolve): any => setTimeout(resolve, 150)); const data = await request.refresh(); // Payment reference should be fixed @@ -1476,7 +1483,7 @@ describe('request-client.js', () => { ), ).toBe('efce79375b2db9f7'); - jest.advanceTimersByTime(150); + await new Promise((resolve): any => setTimeout(resolve, 150)); let dataAfterRefresh = await request.refresh(); expect(dataAfterRefresh.balance).toBeNull(); @@ -1499,9 +1506,7 @@ describe('request-client.js', () => { expect(dataAfterRefresh.balance?.events[0].parameters!.txHash).toBe( '0x06d95c3889dcd974106e82fa27358549d9392d6fee6ea14fe1acedadc1013114', ); - - jest.useRealTimers(); - }); + }, 60000); }); describe('ERC20 address based requests', () => { diff --git a/packages/smart-contracts/hardhat.config.ts b/packages/smart-contracts/hardhat.config.ts index bfb8985cbb..96e0951cea 100644 --- a/packages/smart-contracts/hardhat.config.ts +++ b/packages/smart-contracts/hardhat.config.ts @@ -22,7 +22,6 @@ import { tenderlyImportAll } from './scripts-create2/tenderly'; import { updateContractsFromList } from './scripts-create2/update-contracts-setup'; import deployStorage from './scripts/deploy-storage'; import { transferOwnership } from './scripts-create2/transfer-ownership'; -import deployERC20CommerceEscrowWrapper from './scripts/deploy-erc20-commerce-escrow-wrapper'; config(); @@ -414,17 +413,3 @@ subtask(DEPLOYER_KEY_GUARD, 'prevent usage of the deployer master key').setActio throw new Error('The deployer master key should not be used for this action'); } }); - -task( - 'deploy-erc20-commerce-escrow-wrapper', - 'Deploy ERC20CommerceEscrowWrapper and its dependencies', -) - .addFlag('dryRun', 'to prevent any deployment') - .addFlag('force', 'to force re-deployment') - .setAction(async (args, hre) => { - args.force = args.force ?? false; - args.dryRun = args.dryRun ?? false; - args.simulate = args.dryRun; - await hre.run(DEPLOYER_KEY_GUARD); - await deployERC20CommerceEscrowWrapper(args, hre); - }); diff --git a/packages/smart-contracts/scripts/deploy-base-sepolia.sh b/packages/smart-contracts/scripts/deploy-base-sepolia.sh deleted file mode 100755 index c3fba74396..0000000000 --- a/packages/smart-contracts/scripts/deploy-base-sepolia.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -# Base Sepolia Deployment Script -# This script helps deploy ERC20FeeProxy and ERC20CommerceEscrowWrapper to Base Sepolia - -set -e # Exit on error - -echo "╔═══════════════════════════════════════════════════════════╗" -echo "║ Base Sepolia Deployment Helper Script ║" -echo "║ Request Network - ERC20 Commerce Escrow Wrapper ║" -echo "╚═══════════════════════════════════════════════════════════╝" -echo "" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Load .env file if it exists -if [ -f .env ]; then - echo -e "${BLUE}Loading .env file...${NC}" - set -a - source .env - set +a - echo "" -fi - -# Check if private key is set -if [ -z "$DEPLOYMENT_PRIVATE_KEY" ] && [ -z "$ADMIN_PRIVATE_KEY" ]; then - echo -e "${RED}❌ Error: No private key found!${NC}" - echo "" - echo "Please set either DEPLOYMENT_PRIVATE_KEY or ADMIN_PRIVATE_KEY environment variable:" - echo "" - echo -e "${YELLOW}export DEPLOYMENT_PRIVATE_KEY=your_private_key_here${NC}" - echo "" - echo "OR" - echo "" - echo -e "${YELLOW}export ADMIN_PRIVATE_KEY=your_private_key_here${NC}" - echo "" - echo "⚠️ Make sure to fund your wallet with Base Sepolia ETH:" - echo " https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet" - exit 1 -fi - -echo -e "${GREEN}✓${NC} Private key found" -echo "" - -# Network information -echo -e "${BLUE}Network Information:${NC}" -echo " Name: Base Sepolia" -echo " Chain ID: 84532" -echo " RPC URL: https://sepolia.base.org" -echo " Explorer: https://sepolia.basescan.org/" -echo "" - -# Check if contracts are built -if [ ! -d "build" ]; then - echo -e "${YELLOW}⚠️ Contracts not built. Building now...${NC}" - yarn build:sol - echo "" -fi - -echo -e "${BLUE}Deployment Plan:${NC}" -echo " 1. Deploy ERC20FeeProxy" -echo " 2. Use official AuthCaptureEscrow: 0xBdEA0D1bcC5966192B070Fdf62aB4EF5b4420cff" -echo " 3. Deploy ERC20CommerceEscrowWrapper" -echo "" - -# Ask for confirmation -read -p "Do you want to proceed with deployment? (y/n) " -n 1 -r -echo "" - -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo -e "${YELLOW}Deployment cancelled.${NC}" - exit 0 -fi - -echo "" -echo -e "${GREEN}Starting deployment...${NC}" -echo "" - -# Run deployment -yarn hardhat deploy-erc20-commerce-escrow-wrapper --network base-sepolia - -echo "" -echo -e "${GREEN}╔═══════════════════════════════════════════════════════════╗${NC}" -echo -e "${GREEN}║ Deployment Complete! ║${NC}" -echo -e "${GREEN}╚═══════════════════════════════════════════════════════════╝${NC}" -echo "" -echo -e "${YELLOW}📝 Next Steps:${NC}" -echo "" -echo "1. Update the deployed addresses in these files:" -echo " - packages/smart-contracts/src/lib/artifacts/ERC20FeeProxy/index.ts" -echo " - packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts" -echo "" -echo "2. Rebuild the packages:" -echo " cd packages/smart-contracts && yarn build" -echo "" -echo "3. Verify contracts were verified on Basescan:" -echo " https://sepolia.basescan.org/" -echo "" -echo -e "${BLUE}ℹ️ For more information, see BASE_SEPOLIA_DEPLOYMENT_GUIDE.md${NC}" -echo "" - diff --git a/packages/smart-contracts/scripts/deploy-erc20-commerce-escrow-wrapper.ts b/packages/smart-contracts/scripts/deploy-erc20-commerce-escrow-wrapper.ts deleted file mode 100644 index 3b4f1eb5c1..0000000000 --- a/packages/smart-contracts/scripts/deploy-erc20-commerce-escrow-wrapper.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { deployOne } from './deploy-one'; - -// Base Mainnet & Base Sepolia Contract Addresses -const BASE_SEPOLIA_CONTRACTS = { - AuthCaptureEscrow: '0xBdEA0D1bcC5966192B070Fdf62aB4EF5b4420cff', - ERC3009PaymentCollector: '0x0E3dF9510de65469C4518D7843919c0b8C7A7757', - Permit2PaymentCollector: '0x992476B9Ee81d52a5BdA0622C333938D0Af0aB26', - PreApprovalPaymentCollector: '0x1b77ABd71FCD21fbe2398AE821Aa27D1E6B94bC6', - SpendPermissionPaymentCollector: '0x8d9F34934dc9619e5DC3Df27D0A40b4A744E7eAa', - OperatorRefundCollector: '0x934907bffd0901b6A21e398B9C53A4A38F02fa5d', -}; - -/** - * Deploy ERC20CommerceEscrowWrapper using official Base contracts - * - * This script will: - * 1. Deploy ERC20FeeProxy if not already deployed - * 2. Use the official AuthCaptureEscrow contract deployed on Base Sepolia - * 3. Deploy ERC20CommerceEscrowWrapper with the above dependencies - */ -export default async function deployERC20CommerceEscrowWrapper( - args: any, - hre: HardhatRuntimeEnvironment, -): Promise<{ - erc20FeeProxyAddress: string; - authCaptureEscrowAddress: string; - erc20CommerceEscrowWrapperAddress: string; -}> { - console.log('\n=== Deploying ERC20CommerceEscrowWrapper and dependencies ==='); - console.log(`Network: ${hre.network.name}`); - console.log(`Chain ID: ${hre.network.config.chainId}`); - - const signers = await hre.ethers.getSigners(); - if (signers.length === 0) { - throw new Error( - 'No signers available. Please set DEPLOYMENT_PRIVATE_KEY or ADMIN_PRIVATE_KEY environment variable.', - ); - } - - const deployer = signers[0]; - console.log(`Deployer: ${deployer.address}`); - console.log(`Deployer balance: ${hre.ethers.utils.formatEther(await deployer.getBalance())} ETH`); - - // Step 1: Deploy ERC20FeeProxy - console.log('\n--- Step 1: Deploying ERC20FeeProxy ---'); - const { address: erc20FeeProxyAddress } = await deployOne(args, hre, 'ERC20FeeProxy', { - verify: true, - }); - console.log(`✅ ERC20FeeProxy deployed at: ${erc20FeeProxyAddress}`); - - // Step 2: Use official AuthCaptureEscrow contract - console.log('\n--- Step 2: Using official AuthCaptureEscrow ---'); - const authCaptureEscrowAddress = BASE_SEPOLIA_CONTRACTS.AuthCaptureEscrow; - console.log(`✅ Using official AuthCaptureEscrow at: ${authCaptureEscrowAddress}`); - - // Step 3: Deploy ERC20CommerceEscrowWrapper - console.log('\n--- Step 3: Deploying ERC20CommerceEscrowWrapper ---'); - const { address: erc20CommerceEscrowWrapperAddress } = await deployOne( - args, - hre, - 'ERC20CommerceEscrowWrapper', - { - constructorArguments: [authCaptureEscrowAddress, erc20FeeProxyAddress], - verify: true, - }, - ); - console.log(`✅ ERC20CommerceEscrowWrapper deployed at: ${erc20CommerceEscrowWrapperAddress}`); - - // Summary - console.log('\n=== Deployment Summary ==='); - console.log(`Network: ${hre.network.name} (Chain ID: ${hre.network.config.chainId})`); - console.log(`ERC20FeeProxy: ${erc20FeeProxyAddress}`); - console.log(`AuthCaptureEscrow (official): ${authCaptureEscrowAddress}`); - console.log(`ERC20CommerceEscrowWrapper: ${erc20CommerceEscrowWrapperAddress}`); - - // Verification info - console.log('\n=== Contract Verification ==='); - console.log('ERC20CommerceEscrowWrapper will be automatically verified on the block explorer.'); - console.log('If verification fails, you can manually verify using:'); - console.log( - `yarn hardhat verify --network ${hre.network.name} ${erc20CommerceEscrowWrapperAddress} ${authCaptureEscrowAddress} ${erc20FeeProxyAddress}`, - ); - - return { - erc20FeeProxyAddress, - authCaptureEscrowAddress, - erc20CommerceEscrowWrapperAddress, - }; -} - -// Note: This script should be run via the Hardhat task: -// yarn hardhat deploy-erc20-commerce-escrow-wrapper --network diff --git a/packages/smart-contracts/scripts/test-base-sepolia-deployment.ts b/packages/smart-contracts/scripts/test-base-sepolia-deployment.ts deleted file mode 100644 index 2bc482c5e3..0000000000 --- a/packages/smart-contracts/scripts/test-base-sepolia-deployment.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { ethers } from 'ethers'; - -/** - * Test script to demonstrate Base Sepolia deployment - * This script creates a temporary wallet and shows the deployment process - */ -async function testBaseSepolia() { - console.log('=== Base Sepolia Deployment Test ===\n'); - - // Generate a random wallet for demonstration - const wallet = ethers.Wallet.createRandom(); - console.log('🔑 Generated test wallet:'); - console.log(` Address: ${wallet.address}`); - console.log(` Private Key: ${wallet.privateKey}`); - console.log(' ⚠️ This is a test wallet - do not use for real funds!\n'); - - // Connect to Base Sepolia - const provider = new ethers.providers.JsonRpcProvider('https://sepolia.base.org'); - const connectedWallet = wallet.connect(provider); - - try { - const balance = await connectedWallet.getBalance(); - console.log(`💰 Wallet balance: ${ethers.utils.formatEther(balance)} ETH`); - - if (balance.eq(0)) { - console.log('\n📝 To deploy to Base Sepolia:'); - console.log('1. Fund this address with Base Sepolia ETH from a faucet:'); - console.log(' - https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet'); - console.log(' - https://sepoliafaucet.com/'); - console.log('\n2. Set environment variable:'); - console.log(` export DEPLOYMENT_PRIVATE_KEY=${wallet.privateKey.slice(2)}`); - console.log('\n3. Run deployment:'); - console.log(' yarn hardhat deploy-erc20-commerce-escrow-wrapper --network base-sepolia'); - } else { - console.log('\n✅ Wallet has funds! You can proceed with deployment.'); - } - } catch (error) { - console.log('❌ Could not connect to Base Sepolia RPC'); - console.log(' Make sure you have internet connection'); - } - - console.log('\n=== Network Information ==='); - console.log('Network: Base Sepolia'); - console.log('Chain ID: 84532'); - console.log('RPC URL: https://sepolia.base.org'); - console.log('Explorer: https://sepolia.basescan.org/'); - console.log('Faucet: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet'); -} - -testBaseSepolia() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/packages/smart-contracts/scripts/update-base-sepolia-addresses.js b/packages/smart-contracts/scripts/update-base-sepolia-addresses.js deleted file mode 100755 index 7949fafd60..0000000000 --- a/packages/smart-contracts/scripts/update-base-sepolia-addresses.js +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node - -/** - * Script to update Base Sepolia contract addresses after deployment - * - * Usage: - * node scripts/update-base-sepolia-addresses.js \ - * --erc20-fee-proxy 0x... \ - * --erc20-fee-proxy-block 123456 \ - * --escrow-wrapper 0x... \ - * --escrow-wrapper-block 123457 - */ - -const fs = require('fs'); -const path = require('path'); - -// Parse command line arguments -const args = process.argv.slice(2); -const getArg = (name) => { - const index = args.indexOf(name); - return index !== -1 ? args[index + 1] : null; -}; - -const erc20FeeProxyAddress = getArg('--erc20-fee-proxy'); -const erc20FeeProxyBlock = getArg('--erc20-fee-proxy-block'); -const escrowWrapperAddress = getArg('--escrow-wrapper'); -const escrowWrapperBlock = getArg('--escrow-wrapper-block'); - -console.log('╔═══════════════════════════════════════════════════════════╗'); -console.log('║ Base Sepolia Address Update Script ║'); -console.log('╚═══════════════════════════════════════════════════════════╝'); -console.log(''); - -// Validate inputs -if (!erc20FeeProxyAddress || !erc20FeeProxyBlock || !escrowWrapperAddress || !escrowWrapperBlock) { - console.error('❌ Error: Missing required arguments\n'); - console.log('Usage:'); - console.log(' node scripts/update-base-sepolia-addresses.js \\'); - console.log(' --erc20-fee-proxy 0x... \\'); - console.log(' --erc20-fee-proxy-block 123456 \\'); - console.log(' --escrow-wrapper 0x... \\'); - console.log(' --escrow-wrapper-block 123457\n'); - process.exit(1); -} - -console.log('Addresses to update:'); -console.log(` ERC20FeeProxy: ${erc20FeeProxyAddress} (block ${erc20FeeProxyBlock})`); -console.log(` ERC20CommerceEscrowWrapper: ${escrowWrapperAddress} (block ${escrowWrapperBlock})`); -console.log(''); - -// Update ERC20FeeProxy artifact -const erc20FeeProxyPath = path.join(__dirname, '../src/lib/artifacts/ERC20FeeProxy/index.ts'); - -console.log('Updating ERC20FeeProxy artifact...'); -let erc20FeeProxyContent = fs.readFileSync(erc20FeeProxyPath, 'utf8'); - -// Replace placeholder address and block number for base-sepolia -erc20FeeProxyContent = erc20FeeProxyContent.replace( - /'base-sepolia':\s*\{[\s\S]*?address:\s*'0x0+',[\s\S]*?creationBlockNumber:\s*0,[\s\S]*?\}/, - `'base-sepolia': {\n address: '${erc20FeeProxyAddress}',\n creationBlockNumber: ${erc20FeeProxyBlock},\n }`, -); - -fs.writeFileSync(erc20FeeProxyPath, erc20FeeProxyContent, 'utf8'); -console.log('✅ Updated ERC20FeeProxy artifact'); - -// Update ERC20CommerceEscrowWrapper artifact -const escrowWrapperPath = path.join( - __dirname, - '../src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts', -); - -console.log('Updating ERC20CommerceEscrowWrapper artifact...'); -let escrowWrapperContent = fs.readFileSync(escrowWrapperPath, 'utf8'); - -// Replace placeholder address and block number for base-sepolia -escrowWrapperContent = escrowWrapperContent.replace( - /'base-sepolia':\s*\{[\s\S]*?address:\s*'0x0+',[\s\S]*?creationBlockNumber:\s*0,[\s\S]*?\}/, - `'base-sepolia': {\n address: '${escrowWrapperAddress}',\n creationBlockNumber: ${escrowWrapperBlock},\n }`, -); - -fs.writeFileSync(escrowWrapperPath, escrowWrapperContent, 'utf8'); -console.log('✅ Updated ERC20CommerceEscrowWrapper artifact'); - -console.log(''); -console.log('╔═══════════════════════════════════════════════════════════╗'); -console.log('║ Update Complete! ║'); -console.log('╚═══════════════════════════════════════════════════════════╝'); -console.log(''); -console.log('📝 Next Steps:'); -console.log(''); -console.log('1. Rebuild the smart-contracts package:'); -console.log(' cd packages/smart-contracts && yarn build'); -console.log(''); -console.log('2. Verify the addresses on Base Sepolia Explorer:'); -console.log(` ERC20FeeProxy: https://sepolia.basescan.org/address/${erc20FeeProxyAddress}`); -console.log( - ` ERC20CommerceEscrowWrapper: https://sepolia.basescan.org/address/${escrowWrapperAddress}`, -); -console.log(''); -console.log('3. Test the integration with the SDK'); -console.log(''); diff --git a/packages/smart-contracts/src/lib/artifacts/AuthCaptureEscrow/index.ts b/packages/smart-contracts/src/lib/artifacts/AuthCaptureEscrow/index.ts index 1048bd888a..180ee44c1c 100644 --- a/packages/smart-contracts/src/lib/artifacts/AuthCaptureEscrow/index.ts +++ b/packages/smart-contracts/src/lib/artifacts/AuthCaptureEscrow/index.ts @@ -13,12 +13,12 @@ export const authCaptureEscrowArtifact = new ContractArtifact address: '0x0000000000000000000000000000000000000000', creationBlockNumber: 0, }, - // Base Sepolia deployment (same address as mainnet via CREATE2) + // Sepolia deployment sepolia: { - address: '0x1234567890123456789012345678901234567890', // Placeholder - to be updated with actual deployment - creationBlockNumber: 0, + address: '0xF81E3F293c92CaCfc0d723d2D8183e39Cc3AEdC7', + creationBlockNumber: 9795220, }, - // Base Mainnet deployment (same address as sepolia via CREATE2) + // Base Mainnet deployment base: { address: '0xBdEA0D1bcC5966192B070Fdf62aB4EF5b4420cff', creationBlockNumber: 29931650, diff --git a/packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts b/packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts index 488f535e12..28775dc91b 100644 --- a/packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts +++ b/packages/smart-contracts/src/lib/artifacts/ERC20CommerceEscrowWrapper/index.ts @@ -13,32 +13,16 @@ export const erc20CommerceEscrowWrapperArtifact = new ContractArtifact( address: '0x1892196E80C4c17ea5100Da765Ab48c1fE2Fb814', creationBlockNumber: 10827274, }, - 'base-sepolia': { - address: '0xCF25317C8AE97513b9be05742BA103bf5DF355F9', // To be updated after deployment - creationBlockNumber: 0, - }, sonic: { address: '0x399F5EE127ce7432E4921a61b8CF52b0af52cbfE', creationBlockNumber: 3974138,