diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 375b1173b..630cdb469 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,6 @@ env: GNOSIS_CHAIN_RPC_URL: ${{ secrets.GNOSIS_CHAIN_RPC_URL }} BASE_RPC_URL: $${{ secrets.BASE_RPC_URL }} FOUNDRY_PROFILE: ci - INFURA_ID: ${{ secrets.INFURA_ID }} WALLET_CONNECT_PROJECT_ID: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} jobs: diff --git a/contracts-core/.env.example b/contracts-core/.env.example index 4777fb8b0..b7951bc4b 100644 --- a/contracts-core/.env.example +++ b/contracts-core/.env.example @@ -1,4 +1,3 @@ -INFURA_ID=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz MNEMONIC=here is where your twelve words mnemonic should be put my friend DEPLOY_GSN=false ETHERSCAN_VERIFICATION_API_KEY="YOUR_API_KEY" diff --git a/contracts-periphery/Makefile b/contracts-periphery/Makefile index 4d6262955..87a435aa5 100644 --- a/contracts-periphery/Makefile +++ b/contracts-periphery/Makefile @@ -13,4 +13,4 @@ install :; $(INSTALL_CMD) test :; forge test --sender 0x4f78F7f3482D9f1790649f9DD18Eec5A1Cc70F86 --no-match-contract ApproveBatchSendTokensTest test-gas :; forge test --match-path *.gas.t.sol snapshot-gas :; forge test --match-path *.gas.t.sol --gas-report > snapshot/.gas -coverage :; forge coverage --report lcov --report summary && sed -i'.bak' 's/SF:/SF:contracts-periphery\//gI' lcov.info +coverage :; forge coverage --sender 0x4f78F7f3482D9f1790649f9DD18Eec5A1Cc70F86 --report lcov --report summary && sed -i'.bak' 's/SF:/SF:contracts-periphery\//gI' lcov.info diff --git a/contracts-periphery/script/ApproveBatchSendTokens.s.sol b/contracts-periphery/script/ApproveBatchSendTokens.s.sol index 0ce27a100..5f29461a0 100644 --- a/contracts-periphery/script/ApproveBatchSendTokens.s.sol +++ b/contracts-periphery/script/ApproveBatchSendTokens.s.sol @@ -7,11 +7,12 @@ import {UmbraBatchSend} from "src/UmbraBatchSend.sol"; contract ApproveBatchSendTokens is Script { function run( + address _owner, address _umbraContractAddress, address _batchSendContractAddress, address[] calldata _tokenAddressesToApprove ) public { - vm.startBroadcast(); + vm.startBroadcast(_owner); for (uint256 _i = 0; _i < _tokenAddressesToApprove.length; _i++) { uint256 _currentAllowance = IERC20(_tokenAddressesToApprove[_i]).allowance( _batchSendContractAddress, _umbraContractAddress diff --git a/contracts-periphery/script/DeployBatchSend.s.sol b/contracts-periphery/script/DeployBatchSend.s.sol index 31ead2d4a..d840a5d5c 100644 --- a/contracts-periphery/script/DeployBatchSend.s.sol +++ b/contracts-periphery/script/DeployBatchSend.s.sol @@ -30,7 +30,7 @@ contract DeployBatchSend is Script { /// @notice Deploy the contract to the list of networks, function run() public { // Compute the address the contract will be deployed to - address expectedContractAddress = computeCreateAddress(msg.sender, EXPECTED_NONCE); + address expectedContractAddress = vm.computeCreateAddress(msg.sender, EXPECTED_NONCE); console2.log("Expected contract address: %s", expectedContractAddress); // Turn off fallback to default RPC URLs since they can be flaky. diff --git a/contracts-periphery/test/ApproveBatchSendTokens.t.sol b/contracts-periphery/test/ApproveBatchSendTokens.t.sol index cd7c29a0a..db28cd580 100644 --- a/contracts-periphery/test/ApproveBatchSendTokens.t.sol +++ b/contracts-periphery/test/ApproveBatchSendTokens.t.sol @@ -17,6 +17,7 @@ contract ApproveBatchSendTokensTest is Test { address constant WBTC_ADDRESS = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; address[] tokensToApprove = [DAI_ADDRESS, LUSD_ADDRESS, RAI_ADDRESS, USDC_ADDRESS, USDT_ADDRESS, WBTC_ADDRESS]; + address owner = 0xB7EE870E2c49B2DEEe70003519cF056247Aac3D4; function setUp() public { vm.createSelectFork(vm.rpcUrl("mainnet"), 18_428_858); @@ -27,7 +28,10 @@ contract ApproveBatchSendTokensTest is Test { address[] memory tokenAddressesToApprove = new address[](1); tokenAddressesToApprove[0] = DAI_ADDRESS; approveTokensScript.run( - umbraContractAddressOnMainnet, batchSendContractAddressOnMainnet, tokenAddressesToApprove + owner, + umbraContractAddressOnMainnet, + batchSendContractAddressOnMainnet, + tokenAddressesToApprove ); assertEq( @@ -40,7 +44,7 @@ contract ApproveBatchSendTokensTest is Test { function test_ApproveMultipleTokens() public { approveTokensScript.run( - umbraContractAddressOnMainnet, batchSendContractAddressOnMainnet, tokensToApprove + owner, umbraContractAddressOnMainnet, batchSendContractAddressOnMainnet, tokensToApprove ); for (uint256 _i; _i < tokensToApprove.length; _i++) { diff --git a/contracts-periphery/test/DeployBatchSend.t.sol b/contracts-periphery/test/DeployBatchSend.t.sol index aeb185f33..4fd04797c 100644 --- a/contracts-periphery/test/DeployBatchSend.t.sol +++ b/contracts-periphery/test/DeployBatchSend.t.sol @@ -14,7 +14,7 @@ contract DeployBatchSendTest is DeployBatchSend, Test { bytes batchSendCode; function setUp() public { - expectedContractAddress = computeCreateAddress(sender, EXPECTED_NONCE); + expectedContractAddress = vm.computeCreateAddress(sender, EXPECTED_NONCE); umbraBatchSendTest = new UmbraBatchSend(IUmbra(UMBRA)); batchSendCode = address(umbraBatchSendTest).code; } diff --git a/contracts-periphery/test/UmbraBatchSend.t.sol b/contracts-periphery/test/UmbraBatchSend.t.sol index 65f1b602d..25eb3c20e 100644 --- a/contracts-periphery/test/UmbraBatchSend.t.sol +++ b/contracts-periphery/test/UmbraBatchSend.t.sol @@ -20,6 +20,18 @@ abstract contract UmbraBatchSendTest is DeployUmbraTest { error NotSorted(); error TooMuchEthSent(); + function _sortSendDataByToken(UmbraBatchSend.SendData[] storage arr) internal { + for (uint256 i = 0; i < arr.length - 1; i++) { + for (uint256 j = 0; j < arr.length - i - 1; j++) { + if (arr[j].tokenAddr > arr[j + 1].tokenAddr) { + UmbraBatchSend.SendData memory temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } + } + function setUp() public virtual override { super.setUp(); router = new UmbraBatchSend(IUmbra(address(umbra))); @@ -94,6 +106,8 @@ abstract contract UmbraBatchSendTest is DeployUmbraTest { sendData.push(UmbraBatchSend.SendData(alice, address(token), amount, pkx, ciphertext)); sendData.push(UmbraBatchSend.SendData(bob, address(token), amount2, pkx, ciphertext)); + _sortSendDataByToken(sendData); + uint256 totalToll = toll * sendData.length; token.approve(address(router), totalAmount); token2.approve(address(router), totalAmount2); diff --git a/frontend/.env.example b/frontend/.env.example index ee9dccc1b..3062ba0bd 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -3,7 +3,6 @@ OPTIMISTIC_ETHERSCAN_API_KEY=yourOptimisticEtherscanApiKey POLYGONSCAN_API_KEY=yourPolygonscanApiKey ARBISCAN_API_KEY=yourArbiscanApiKey -INFURA_ID=yourKeyHere BLOCKNATIVE_API_KEY=yourKeyHere FORTMATIC_API_KEY=yourKeyHere PORTIS_API_KEY=yourKeyHere diff --git a/umbra-js/.env.example b/umbra-js/.env.example index 0317f16b1..0b36f09e2 100644 --- a/umbra-js/.env.example +++ b/umbra-js/.env.example @@ -3,7 +3,6 @@ OPTIMISTIC_ETHERSCAN_API_KEY=yourOptimisticEtherscanApiKey POLYGONSCAN_API_KEY=yourPolygonscanApiKey ARBISCAN_API_KEY=yourArbiscanApiKey GNOSISSCAN_API_KEY=yourGnosisSafeScanApiKey -INFURA_ID=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz MAINNET_RPC_URL=yourMainnetRpcUrl OPTIMISM_RPC_URL=yourOptimismRpcUrl GNOSIS_CHAIN_RPC_URL=yourGnosisChainRpcUrl diff --git a/umbra-js/hardhat.config.ts b/umbra-js/hardhat.config.ts index cf6fe252f..1d97311dc 100644 --- a/umbra-js/hardhat.config.ts +++ b/umbra-js/hardhat.config.ts @@ -19,11 +19,10 @@ const chainIds = { // Ensure that we have all the environment variables we need. const mnemonic = 'test test test test test test test test test test test junk'; -const infuraApiKey = process.env.INFURA_ID; -if (!infuraApiKey) throw new Error('Please set your INFURA_ID in a .env file'); - function createTestnetConfig(network: keyof typeof chainIds): NetworkUserConfig { - const url = `https://${network}.infura.io/v3/${infuraApiKey as string}`; + const rpcUrlString = `${network.toUpperCase()}_RPC_URL`; + const url = process.env[rpcUrlString]; + if (!url) throw new Error(`Please set the ${url} in a .env file`); return { accounts: { count: 10, @@ -36,12 +35,14 @@ function createTestnetConfig(network: keyof typeof chainIds): NetworkUserConfig }; } +const rpcUrlString = process.env.SEPOLIA_RPC_URL; +if (!rpcUrlString) throw new Error('Please set the SEPOLIA_RPC_URL in a .env file'); const config: HardhatUserConfig = { defaultNetwork: 'hardhat', networks: { hardhat: { forking: { - url: `https://sepolia.infura.io/v3/${infuraApiKey}`, + url: rpcUrlString, }, chainId: chainIds.hardhat, accounts: { diff --git a/umbra-js/test/cns.test.ts b/umbra-js/test/cns.test.ts index 9f6933161..20f1dad15 100644 --- a/umbra-js/test/cns.test.ts +++ b/umbra-js/test/cns.test.ts @@ -11,11 +11,11 @@ const resolution = new Resolution({ uns: { locations: { Layer1: { - url: `https://mainnet.infura.io/v3/${String(process.env.INFURA_ID)}`, + url: `${String(process.env.MAINNET_RPC_URL)}`, network: 'mainnet', }, Layer2: { - url: `https://polygon-mainnet.infura.io/v3/${String(process.env.INFURA_ID)}`, + url: `${String(process.env.POLYGON_RPC_URL)}`, network: 'polygon-mainnet', }, }, @@ -43,9 +43,7 @@ describe('СNS functions', () => { it('gets the public keys associated with a CNS address', async () => { const address = await resolution.addr(name, 'ETH'); - const ethersProvider = new StaticJsonRpcProvider( - `https://polygon-mainnet.infura.io/v3/${String(process.env.INFURA_ID)}` - ); + const ethersProvider = new StaticJsonRpcProvider(`${String(process.env.POLYGON_RPC_URL)}`); const keys = await utils.lookupRecipient(address, ethersProvider); expect(keys.spendingPublicKey).to.equal(nameSpendingPublicKey); expect(keys.viewingPublicKey).to.equal(nameViewingPublicKey); diff --git a/umbra-js/test/utils.test.ts b/umbra-js/test/utils.test.ts index 86c42b244..37ae2afa5 100644 --- a/umbra-js/test/utils.test.ts +++ b/umbra-js/test/utils.test.ts @@ -8,8 +8,20 @@ import { Event } from '../src/ethers'; const ethersProvider = ethers.provider; -const INFURA_ID = process.env.INFURA_ID; -if (!INFURA_ID) throw new Error('Please set your INFURA_ID in a .env file'); +const MAINNET_RPC_URL = process.env.MAINNET_RPC_URL; +if (!MAINNET_RPC_URL) throw new Error('Please set your MAINNET_RPC_URL in a .env file'); + +const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL; +if (!SEPOLIA_RPC_URL) throw new Error('Please set your SEPOLIA_RPC_URL in a .env file'); + +const POLYGON_RPC_URL = process.env.POLYGON_RPC_URL; +if (!POLYGON_RPC_URL) throw new Error('Please set your POLYGON_RPC_URL in a .env file'); + +const OPTIMISM_RPC_URL = process.env.OPTIMISM_RPC_URL; +if (!OPTIMISM_RPC_URL) throw new Error('Please set your OPTIMISM_RPC_URL in a .env file'); + +const ARBITRUM_ONE_RPC_URL = process.env.ARBITRUM_ONE_RPC_URL; +if (!ARBITRUM_ONE_RPC_URL) throw new Error('Please set your ARBITRUM_ONE_RPC_URL in a .env file'); // Public key and address corresponding to stratus4.eth const publicKey = '0x04458465db23fe07d148c8c9078d8b67497998a66f4f2aa479973a9cbaaf8b5a96e6ba166a389b8f794b68010849b64b91343e72c7fa4cfcc178607c4b1d4870ed'; // prettier-ignore @@ -109,21 +121,21 @@ describe('Utilities', () => { // --- Address, advanced mode on (i.e. don't use the StealthKeyRegistry) --- it('looks up recipients by address, advanced mode on', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${String(process.env.INFURA_ID)}`); + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); const keys = await utils.lookupRecipient(address, ethersProvider, { advanced: true }); expect(keys.spendingPublicKey).to.equal(pubKeysWallet.spendingPublicKey); expect(keys.viewingPublicKey).to.equal(pubKeysWallet.viewingPublicKey); }); it('looks up recipients by ENS, advanced mode on', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${String(process.env.INFURA_ID)}`); + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); const keys = await utils.lookupRecipient('stratus4.eth', ethersProvider, { advanced: true }); expect(keys.spendingPublicKey).to.equal(pubKeysWallet.spendingPublicKey); expect(keys.viewingPublicKey).to.equal(pubKeysWallet.viewingPublicKey); }); it.skip('looks up recipients by CNS, advanced mode on', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${INFURA_ID}`); + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); const keys = await utils.lookupRecipient('udtestdev-msolomon.crypto', ethersProvider, { advanced: true }); expect(keys.spendingPublicKey).to.equal(pubKeysWallet.spendingPublicKey); expect(keys.viewingPublicKey).to.equal(pubKeysWallet.viewingPublicKey); @@ -131,7 +143,7 @@ describe('Utilities', () => { // --- Address, advanced mode off (i.e. use the StealthKeyRegistry) --- it('looks up recipients by address, advanced mode off', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${INFURA_ID}`); // otherwise throws with unsupported network since we're on localhost + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); // otherwise throws with unsupported network since we're on localhost const keys = await utils.lookupRecipient(address, ethersProvider); expect(keys.spendingPublicKey).to.equal(pubKeysUmbra.spendingPublicKey); expect(keys.viewingPublicKey).to.equal(pubKeysUmbra.viewingPublicKey); @@ -143,7 +155,7 @@ describe('Utilities', () => { }); it('looks up recipients by ENS, advanced mode off', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${INFURA_ID}`); + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); const keys = await utils.lookupRecipient('stratus4.eth', ethersProvider); // These values are set on the Sepolia resolver expect(keys.spendingPublicKey).to.equal(pubKeysUmbra.spendingPublicKey); @@ -181,37 +193,31 @@ describe('Utilities', () => { // --- Address history by network --- it('looks up transaction history on mainnet', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://mainnet.infura.io/v3/${INFURA_ID}`); + const ethersProvider = new StaticJsonRpcProvider(MAINNET_RPC_URL); const txHash = await utils.getSentTransaction(address, ethersProvider); expect(txHash).to.have.lengthOf(66); }); it('looks up transaction history on sepolia', async () => { - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${INFURA_ID}`); + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); const txHash = await utils.getSentTransaction(address, ethersProvider); expect(txHash).to.have.lengthOf(66); }); it('looks up transaction history on polygon', async () => { - const ethersProvider = new ethers.providers.StaticJsonRpcProvider( - `https://polygon-mainnet.infura.io/v3/${INFURA_ID}` - ) as EthersProvider; + const ethersProvider = new ethers.providers.StaticJsonRpcProvider(POLYGON_RPC_URL) as EthersProvider; const txHash = await utils.getSentTransaction(address, ethersProvider); expect(txHash).to.have.lengthOf(66); }); it('looks up transaction history on optimism', async () => { - const ethersProvider = new ethers.providers.StaticJsonRpcProvider( - `https://optimism-mainnet.infura.io/v3/${INFURA_ID}` - ) as EthersProvider; + const ethersProvider = new ethers.providers.StaticJsonRpcProvider(OPTIMISM_RPC_URL) as EthersProvider; const txHash = await utils.getSentTransaction(address, ethersProvider); expect(txHash).to.have.lengthOf(66); }); it('looks up transaction history on arbitrum one', async () => { - const ethersProvider = new ethers.providers.StaticJsonRpcProvider( - `https://arbitrum-mainnet.infura.io/v3/${INFURA_ID}` - ) as EthersProvider; + const ethersProvider = new ethers.providers.StaticJsonRpcProvider(ARBITRUM_ONE_RPC_URL) as EthersProvider; const txHash = await utils.getSentTransaction(address, ethersProvider); expect(txHash).to.have.lengthOf(66); }); @@ -238,7 +244,7 @@ describe('Utilities', () => { it('throws when looking up an address that has not sent a transaction', async () => { const address = '0x0000000000000000000000000000000000000002'; - const ethersProvider = new StaticJsonRpcProvider(`https://sepolia.infura.io/v3/${INFURA_ID}`); // otherwise throws with unsupported network since we're on localhost + const ethersProvider = new StaticJsonRpcProvider(SEPOLIA_RPC_URL); // otherwise throws with unsupported network since we're on localhost const errorMsg = `Address ${address} has not registered stealth keys. Please ask them to setup their Umbra account`; await expectRejection(utils.lookupRecipient(address, ethersProvider), errorMsg); });