Skip to content

Commit

Permalink
Umbra-js and frontend support for Base network (#643)
Browse files Browse the repository at this point in the history
* UmbraJs and frontend support for Base network

* Bumped package version to 0.1.5

* Updated startBlock of Umbra chain config for base

* Added Base chain to the UmbraJS class test

* Fix typo that was causing failing test

* Use alchemy for Base network subgraph in umbra-js

* Fix chainId used for announcements fetching error message on Base

* Updated umbra-js dependency to version 0.1.5 for Base support

* Move subgraph urls to .env

* Remove `subgraphUrl` checks in test

* Update umbra-js version to 0.1.6

* Update CI file with subgraph secrets

---------

Co-authored-by: garyghayrat <[email protected]>
  • Loading branch information
jferas and garyghayrat authored Apr 22, 2024
1 parent 1dfa693 commit 4e3efd4
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 34 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ env:
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} # Mainnet.
OPTIMISTIC_ETHERSCAN_API_KEY: ${{ secrets.OPTIMISTIC_ETHERSCAN_API_KEY }}
POLYGONSCAN_API_KEY: ${{ secrets.POLYGONSCAN_API_KEY }}
# Subgraphs
MAINNET_SUBGRAPH_URL: ${{ secrets.MAINNET_SUBGRAPH_URL }}
OPTIMISM_SUBGRAPH_URL: ${{ secrets.OPTIMISM_SUBGRAPH_URL }}
GNOSIS_CHAIN_SUBGRAPH_URL: ${{ secrets.GNOSIS_CHAIN_SUBGRAPH_URL }}
POLYGON_SUBGRAPH_URL: ${{ secrets.POLYGON_SUBGRAPH_URL }}
BASE_SUBGRAPH_URL: ${{ secrets.BASE_SUBGRAPH_URL }}
ARBITRUM_ONE_SUBGRAPH_URL: ${{ secrets.ARBITRUM_ONE_SUBGRAPH_URL }}
SEPOLIA_SUBGRAPH_URL: ${{ secrets.SEPOLIA_SUBGRAPH_URL }}
# Other.
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
Expand Down Expand Up @@ -176,7 +184,7 @@ jobs:
- uses: volta-cli/action@v4
with:
cache: false
- name: Look at directory
- name: Look at directory
run: ls -la
- name: Install Typescript
run: volta run yarn global add typescript@^4.0.3
Expand Down
9 changes: 9 additions & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ OPTIMISM_RPC_URL=yourRpcUrlHere
GNOSIS_CHAIN_RPC_URL=yourRpcUrlHere
ARBITRUM_ONE_RPC_URL=yourRpcUrlHere
SEPOLIA_RPC_URL=yourSepoliaRpcUrl
BASE_RPC_URL=yourBaseRpcUrl
WALLET_CONNECT_PROJECT_ID=yourId

MAINNET_SUBGRAPH_URL=
OPTIMISM_SUBGRAPH_URL=
GNOSIS_CHAIN_SUBGRAPH_URL=
POLYGON_SUBGRAPH_URL=
BASE_SUBGRAPH_URL=
ARBITRUM_ONE_SUBGRAPH_URL=
SEPOLIA_SUBGRAPH_URL=

LOG_LEVEL=DEBUG
MAINTENANCE_MODE_SEND=0
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@adraffy/ens-normalize": "1.9.2",
"@metamask/jazzicon": "^2.0.0",
"@quasar/extras": "^1.15.8",
"@umbracash/umbra-js": "^0.1.0",
"@umbracash/umbra-js": "0.1.6",
"@uniswap/token-lists": "^1.0.0-beta.19",
"@unstoppabledomains/resolution": "8.5.0",
"@web3-onboard/coinbase": "^2.2.5",
Expand Down
6 changes: 6 additions & 0 deletions frontend/public/networks/base.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<!-- Custom fees not allowed on L2s, since gas price is affected by
both L1 and L2 costs, so users will likely not estimate it properly -->
<q-icon
v-if="isNativeToken && loaded && ![10, 42161].includes(chainId)"
v-if="isNativeToken && loaded && ![10, 8453, 42161].includes(chainId)"
@click="toggleCustomFee"
class="cursor-pointer"
color="primary"
Expand Down Expand Up @@ -220,9 +220,9 @@ export default defineComponent({
const from = propsRef.activeAnnouncement.value.receiver;
const to = await toAddress(propsRef.destinationAddress.value, provider.value!);
// On Optimism, we use Umbra's getEthSweepGasInfo method to ensure L1 fees are accounted for.
// On Optimism or Base, we use Umbra's getEthSweepGasInfo method to ensure L1 fees are accounted for.
// Otherwise we use the standard gasPrice * gasLimit as the default.
if (network.value?.chainId === 10) {
if (network.value?.chainId === 10 || network.value?.chainId === 8453) {
const { getEthSweepGasInfo } = umbraUtils;
const sweepGasInfo = await getEthSweepGasInfo(from, to, provider.value!);
gasLimit.value = sweepGasInfo.gasLimit;
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/components/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SEPOLIA_RPC_URL,
ARBITRUM_ONE_RPC_URL,
GNOSIS_CHAIN_RPC_URL,
BASE_RPC_URL,
} from 'src/utils/constants';

export type { TokenList, TokenInfo } from '@uniswap/token-lists/dist/types';
Expand Down Expand Up @@ -123,6 +124,21 @@ export const supportedChains: Array<Chain> = [
iconUrls: ['/networks/polygon.svg'],
logoURI: '/networks/polygon.svg',
},
{
chainId: '0x2105', // 8453 as hex
chainName: 'Base',
nativeCurrency: {
address: NATIVE_TOKEN_ADDRESS,
name: 'Ether',
symbol: 'ETH',
decimals: 18,
logoURI: ETH_NETWORK_LOGO,
},
rpcUrls: ['https://mainnet.base.org', BASE_RPC_URL],
blockExplorerUrls: ['https://basescan.org'],
iconUrls: ['/networks/base.svg'],
logoURI: '/networks/base.svg',
},
{
chainId: '0xa4b1', // 42161 as hex
chainName: 'Arbitrum One',
Expand All @@ -141,7 +157,7 @@ export const supportedChains: Array<Chain> = [
];

// Set comprised of intersection of Chain IDs present for all contracts in src/contracts, supported by umbra-js, and by relayer
export type SupportedChainId = '1' | '10' | '100' | '137' | '42161' | '11155111'; // strings for indexing into JSON files
export type SupportedChainId = '1' | '10' | '100' | '137' | '8453' | '42161' | '11155111'; // strings for indexing into JSON files
export const supportedChainIds = supportedChains.map((chain) => Number(chain.chainId)); // numbers for verifying the chainId user is connected to

// CNS names owned by wallet are queried from The Graph, so these types help parse the response
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/AccountSend.vue
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ function useSendForm() {
const batchSends = ref<BatchSendData[]>([]);
const tab = ref('send');
const previousTabChecked = ref('send');
const batchSendSupportedChains = [1, 10, 100, 137, 42161, 11155111];
const batchSendSupportedChains = [1, 10, 100, 137, 8453, 42161, 11155111];
const batchSendIsSupported = ref(false);
const numberOfErrorOrWarningBreaksNeeded = ref(0);
Expand Down
1 change: 1 addition & 0 deletions frontend/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const OPTIMISM_RPC_URL = String(process.env.OPTIMISM_RPC_URL);
export const ARBITRUM_ONE_RPC_URL = String(process.env.ARBITRUM_ONE_RPC_URL);
export const SEPOLIA_RPC_URL = String(process.env.SEPOLIA_RPC_URL);
export const GNOSIS_CHAIN_RPC_URL = String(process.env.GNOSIS_CHAIN_RPC_URL);
export const BASE_RPC_URL = String(process.env.BASE_RPC_URL);

console.log(`MAINNET_RPC_URL ${MAINNET_RPC_URL}`);

Expand Down
2 changes: 2 additions & 0 deletions umbra-js/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ GNOSIS_CHAIN_RPC_URL=yourGnosisChainRpcUrl
POLYGON_RPC_URL=yourPolygonRpcUrl
ARBITRUM_ONE_RPC_URL=yourArbitrumOneRpcUrl
SEPOLIA_RPC_URL=yourSepoliaRpcUrl
BASE_RPC_URL=yourBaseRpcUrl

2 changes: 1 addition & 1 deletion umbra-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umbracash/umbra-js",
"version": "0.1.4",
"version": "0.1.6",
"description": "Send and receive stealth payments",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
Expand Down
20 changes: 12 additions & 8 deletions umbra-js/src/classes/Umbra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ import type { Announcement, ChainConfig, EthersProvider, GraphFilterOverride, Sc
const umbraAddress = '0xFb2dc580Eed955B528407b4d36FfaFe3da685401'; // same on all supported networks
const batchSendAddress = '0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB'; // same on all supported networks
const subgraphs = {
1: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-mainnet/v1.1.0/gn',
10: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-optimism/v1.1.0/gn',
100: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-xdai/v1.1.0/gn',
137: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-polygon/v1.1.0/gn',
42161: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-arbitrum-one/v1.1.0/gn',
11155111: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-sepolia/v1.1.0/gn',
1: String(process.env.MAINNET_SUBGRAPH_URL),
10: String(process.env.OPTIMISM_SUBGRAPH_URL),
100: String(process.env.GNOSIS_CHAIN_SUBGRAPH_URL),
137: String(process.env.POLYGON_SUBGRAPH_URL),
8453: String(process.env.BASE_SUBGRAPH_URL),
42161: String(process.env.ARBITRUM_ONE_SUBGRAPH_URL),
11155111: String(process.env.SEPOLIA_SUBGRAPH_URL),
};

const chainConfigs: Record<number, ChainConfig> = {
Expand All @@ -56,6 +57,7 @@ const chainConfigs: Record<number, ChainConfig> = {
100: { chainId: 100, umbraAddress, batchSendAddress, startBlock: 28237950, subgraphUrl: subgraphs[100] }, // Gnosis Chain
137: { chainId: 137, umbraAddress, batchSendAddress, startBlock: 20717318, subgraphUrl: subgraphs[137] }, // Polygon
1337: { chainId: 1337, umbraAddress, batchSendAddress, startBlock: 8505089, subgraphUrl: false }, // Local
8453: { chainId: 8453, umbraAddress, batchSendAddress, startBlock: 10761374, subgraphUrl: subgraphs[8453] }, // Base
42161: { chainId: 42161, umbraAddress, batchSendAddress, startBlock: 7285883, subgraphUrl: subgraphs[42161] }, // Arbitrum
11155111: {
chainId: 11155111,
Expand Down Expand Up @@ -128,6 +130,7 @@ const rpcUrlFromChain = (chainId: BigNumberish) => {
if (chainId === 10) return String(process.env.OPTIMISM_RPC_URL);
if (chainId === 100) return String(process.env.GNOSIS_CHAIN_RPC_URL);
if (chainId === 137) return String(process.env.POLYGON_RPC_URL);
if (chainId === 8453) return String(process.env.BASE_RPC_URL);
if (chainId === 42161) return String(process.env.ARBITRUM_ONE_RPC_URL);
if (chainId === 11155111) return String(process.env.SEPOLIA_RPC_URL);
throw new Error(`No RPC URL for chainId ${chainId}.`);
Expand Down Expand Up @@ -492,6 +495,7 @@ export class Umbra {
const errMsg = (network: string) => `Cannot fetch Announcements from logs on ${network}, please try again later`;
if (this.chainConfig.chainId === 10) throw new Error(errMsg('Optimism'));
if (this.chainConfig.chainId === 137) throw new Error(errMsg('Polygon'));
if (this.chainConfig.chainId === 8453) throw new Error(errMsg('Base'));

// Get list of all Announcement events
const announcementFilter = this.umbraContract.filters.Announcement(null, null, null, null, null);
Expand Down Expand Up @@ -809,10 +813,10 @@ async function tryEthWithdraw(
throw new Error('Stealth address ETH balance is not enough to pay for withdrawal gas cost');
}

// If on Optimism, reduce the value sent to add margin for the variable L1 gas costs. The margin added is
// If on Optimismj or Base, reduce the value sent to add margin for the variable L1 gas costs. The margin added is
// proportional to the retryCount, i.e. the more retries, the more margin is added, capped at 20% added cost
let adjustedValue = ethToSend;
if (chainId === 10) {
if (chainId === 10 || chainId === 8453) {
const costWithMargin = txCost.mul(100 + Math.min(retryCount, 20)).div(100);
adjustedValue = adjustedValue.sub(costWithMargin);
}
Expand Down
24 changes: 6 additions & 18 deletions umbra-js/test/Umbra.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,54 +156,42 @@ describe('Umbra class', () => {
expect(umbra3.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra3.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra3.chainConfig.startBlock).to.equal(3590825);
expect(umbra3.chainConfig.subgraphUrl).to.equal(
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-sepolia/v1.1.0/gn'
);

// --- Mainnet ---
const umbra4 = new Umbra(jsonRpcProvider, 1);
expect(umbra4.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra4.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra4.chainConfig.startBlock).to.equal(12343914);
expect(umbra4.chainConfig.subgraphUrl).to.equal(
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-mainnet/v1.1.0/gn'
);

// --- Optimism ---
const umbra5 = new Umbra(jsonRpcProvider, 10);
expect(umbra5.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra5.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra5.chainConfig.startBlock).to.equal(4069556);
expect(umbra5.chainConfig.subgraphUrl).to.equal(
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-optimism/v1.1.0/gn'
);

// --- Gnosis Chain ---
const umbra6 = new Umbra(jsonRpcProvider, 100);
expect(umbra6.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra6.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra6.chainConfig.startBlock).to.equal(28237950);
expect(umbra6.chainConfig.subgraphUrl).to.equal(
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-xdai/v1.1.0/gn'
);

// --- Polygon ---
const umbra7 = new Umbra(jsonRpcProvider, 137);
expect(umbra7.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra7.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra7.chainConfig.startBlock).to.equal(20717318);
expect(umbra7.chainConfig.subgraphUrl).to.equal(
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-polygon/v1.1.0/gn'
);

// --- Arbitrum ---
const umbra8 = new Umbra(jsonRpcProvider, 42161);
expect(umbra8.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra8.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra8.chainConfig.startBlock).to.equal(7285883);
expect(umbra8.chainConfig.subgraphUrl).to.equal(
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-arbitrum-one/v1.1.0/gn'
);

// --- Base ---
const umbra9 = new Umbra(jsonRpcProvider, 8453);
expect(umbra9.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
expect(umbra9.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
expect(umbra9.chainConfig.startBlock).to.equal(10761374);
});

it('does not allow invalid default chain IDs to be provided', async () => {
Expand Down

0 comments on commit 4e3efd4

Please sign in to comment.