Skip to content

Commit 4e3efd4

Browse files
jferasgaryghayrat
andauthored
Umbra-js and frontend support for Base network (#643)
* 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]>
1 parent 1dfa693 commit 4e3efd4

File tree

12 files changed

+68
-34
lines changed

12 files changed

+68
-34
lines changed

.github/workflows/ci.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ env:
1111
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} # Mainnet.
1212
OPTIMISTIC_ETHERSCAN_API_KEY: ${{ secrets.OPTIMISTIC_ETHERSCAN_API_KEY }}
1313
POLYGONSCAN_API_KEY: ${{ secrets.POLYGONSCAN_API_KEY }}
14+
# Subgraphs
15+
MAINNET_SUBGRAPH_URL: ${{ secrets.MAINNET_SUBGRAPH_URL }}
16+
OPTIMISM_SUBGRAPH_URL: ${{ secrets.OPTIMISM_SUBGRAPH_URL }}
17+
GNOSIS_CHAIN_SUBGRAPH_URL: ${{ secrets.GNOSIS_CHAIN_SUBGRAPH_URL }}
18+
POLYGON_SUBGRAPH_URL: ${{ secrets.POLYGON_SUBGRAPH_URL }}
19+
BASE_SUBGRAPH_URL: ${{ secrets.BASE_SUBGRAPH_URL }}
20+
ARBITRUM_ONE_SUBGRAPH_URL: ${{ secrets.ARBITRUM_ONE_SUBGRAPH_URL }}
21+
SEPOLIA_SUBGRAPH_URL: ${{ secrets.SEPOLIA_SUBGRAPH_URL }}
1422
# Other.
1523
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
1624
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
@@ -176,7 +184,7 @@ jobs:
176184
- uses: volta-cli/action@v4
177185
with:
178186
cache: false
179-
- name: Look at directory
187+
- name: Look at directory
180188
run: ls -la
181189
- name: Install Typescript
182190
run: volta run yarn global add typescript@^4.0.3

frontend/.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ OPTIMISM_RPC_URL=yourRpcUrlHere
1414
GNOSIS_CHAIN_RPC_URL=yourRpcUrlHere
1515
ARBITRUM_ONE_RPC_URL=yourRpcUrlHere
1616
SEPOLIA_RPC_URL=yourSepoliaRpcUrl
17+
BASE_RPC_URL=yourBaseRpcUrl
1718
WALLET_CONNECT_PROJECT_ID=yourId
1819

20+
MAINNET_SUBGRAPH_URL=
21+
OPTIMISM_SUBGRAPH_URL=
22+
GNOSIS_CHAIN_SUBGRAPH_URL=
23+
POLYGON_SUBGRAPH_URL=
24+
BASE_SUBGRAPH_URL=
25+
ARBITRUM_ONE_SUBGRAPH_URL=
26+
SEPOLIA_SUBGRAPH_URL=
27+
1928
LOG_LEVEL=DEBUG
2029
MAINTENANCE_MODE_SEND=0

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"@adraffy/ens-normalize": "1.9.2",
2121
"@metamask/jazzicon": "^2.0.0",
2222
"@quasar/extras": "^1.15.8",
23-
"@umbracash/umbra-js": "^0.1.0",
23+
"@umbracash/umbra-js": "0.1.6",
2424
"@uniswap/token-lists": "^1.0.0-beta.19",
2525
"@unstoppabledomains/resolution": "8.5.0",
2626
"@web3-onboard/coinbase": "^2.2.5",

frontend/public/networks/base.svg

Lines changed: 6 additions & 0 deletions
Loading

frontend/src/components/AccountReceiveTableWithdrawConfirmation.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
<!-- Custom fees not allowed on L2s, since gas price is affected by
6262
both L1 and L2 costs, so users will likely not estimate it properly -->
6363
<q-icon
64-
v-if="isNativeToken && loaded && ![10, 42161].includes(chainId)"
64+
v-if="isNativeToken && loaded && ![10, 8453, 42161].includes(chainId)"
6565
@click="toggleCustomFee"
6666
class="cursor-pointer"
6767
color="primary"
@@ -220,9 +220,9 @@ export default defineComponent({
220220
const from = propsRef.activeAnnouncement.value.receiver;
221221
const to = await toAddress(propsRef.destinationAddress.value, provider.value!);
222222
223-
// On Optimism, we use Umbra's getEthSweepGasInfo method to ensure L1 fees are accounted for.
223+
// On Optimism or Base, we use Umbra's getEthSweepGasInfo method to ensure L1 fees are accounted for.
224224
// Otherwise we use the standard gasPrice * gasLimit as the default.
225-
if (network.value?.chainId === 10) {
225+
if (network.value?.chainId === 10 || network.value?.chainId === 8453) {
226226
const { getEthSweepGasInfo } = umbraUtils;
227227
const sweepGasInfo = await getEthSweepGasInfo(from, to, provider.value!);
228228
gasLimit.value = sweepGasInfo.gasLimit;

frontend/src/components/models.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
SEPOLIA_RPC_URL,
1111
ARBITRUM_ONE_RPC_URL,
1212
GNOSIS_CHAIN_RPC_URL,
13+
BASE_RPC_URL,
1314
} from 'src/utils/constants';
1415

1516
export type { TokenList, TokenInfo } from '@uniswap/token-lists/dist/types';
@@ -123,6 +124,21 @@ export const supportedChains: Array<Chain> = [
123124
iconUrls: ['/networks/polygon.svg'],
124125
logoURI: '/networks/polygon.svg',
125126
},
127+
{
128+
chainId: '0x2105', // 8453 as hex
129+
chainName: 'Base',
130+
nativeCurrency: {
131+
address: NATIVE_TOKEN_ADDRESS,
132+
name: 'Ether',
133+
symbol: 'ETH',
134+
decimals: 18,
135+
logoURI: ETH_NETWORK_LOGO,
136+
},
137+
rpcUrls: ['https://mainnet.base.org', BASE_RPC_URL],
138+
blockExplorerUrls: ['https://basescan.org'],
139+
iconUrls: ['/networks/base.svg'],
140+
logoURI: '/networks/base.svg',
141+
},
126142
{
127143
chainId: '0xa4b1', // 42161 as hex
128144
chainName: 'Arbitrum One',
@@ -141,7 +157,7 @@ export const supportedChains: Array<Chain> = [
141157
];
142158

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

147163
// CNS names owned by wallet are queried from The Graph, so these types help parse the response

frontend/src/pages/AccountSend.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ function useSendForm() {
594594
const batchSends = ref<BatchSendData[]>([]);
595595
const tab = ref('send');
596596
const previousTabChecked = ref('send');
597-
const batchSendSupportedChains = [1, 10, 100, 137, 42161, 11155111];
597+
const batchSendSupportedChains = [1, 10, 100, 137, 8453, 42161, 11155111];
598598
const batchSendIsSupported = ref(false);
599599
const numberOfErrorOrWarningBreaksNeeded = ref(0);
600600

frontend/src/utils/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const OPTIMISM_RPC_URL = String(process.env.OPTIMISM_RPC_URL);
88
export const ARBITRUM_ONE_RPC_URL = String(process.env.ARBITRUM_ONE_RPC_URL);
99
export const SEPOLIA_RPC_URL = String(process.env.SEPOLIA_RPC_URL);
1010
export const GNOSIS_CHAIN_RPC_URL = String(process.env.GNOSIS_CHAIN_RPC_URL);
11+
export const BASE_RPC_URL = String(process.env.BASE_RPC_URL);
1112

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

umbra-js/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ GNOSIS_CHAIN_RPC_URL=yourGnosisChainRpcUrl
1010
POLYGON_RPC_URL=yourPolygonRpcUrl
1111
ARBITRUM_ONE_RPC_URL=yourArbitrumOneRpcUrl
1212
SEPOLIA_RPC_URL=yourSepoliaRpcUrl
13+
BASE_RPC_URL=yourBaseRpcUrl
14+

umbra-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@umbracash/umbra-js",
3-
"version": "0.1.4",
3+
"version": "0.1.6",
44
"description": "Send and receive stealth payments",
55
"main": "build/src/index.js",
66
"types": "build/src/index.d.ts",

umbra-js/src/classes/Umbra.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ import type { Announcement, ChainConfig, EthersProvider, GraphFilterOverride, Sc
4242
const umbraAddress = '0xFb2dc580Eed955B528407b4d36FfaFe3da685401'; // same on all supported networks
4343
const batchSendAddress = '0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB'; // same on all supported networks
4444
const subgraphs = {
45-
1: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-mainnet/v1.1.0/gn',
46-
10: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-optimism/v1.1.0/gn',
47-
100: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-xdai/v1.1.0/gn',
48-
137: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-polygon/v1.1.0/gn',
49-
42161: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-arbitrum-one/v1.1.0/gn',
50-
11155111: 'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-sepolia/v1.1.0/gn',
45+
1: String(process.env.MAINNET_SUBGRAPH_URL),
46+
10: String(process.env.OPTIMISM_SUBGRAPH_URL),
47+
100: String(process.env.GNOSIS_CHAIN_SUBGRAPH_URL),
48+
137: String(process.env.POLYGON_SUBGRAPH_URL),
49+
8453: String(process.env.BASE_SUBGRAPH_URL),
50+
42161: String(process.env.ARBITRUM_ONE_SUBGRAPH_URL),
51+
11155111: String(process.env.SEPOLIA_SUBGRAPH_URL),
5152
};
5253

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

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

812-
// If on Optimism, reduce the value sent to add margin for the variable L1 gas costs. The margin added is
816+
// If on Optimismj or Base, reduce the value sent to add margin for the variable L1 gas costs. The margin added is
813817
// proportional to the retryCount, i.e. the more retries, the more margin is added, capped at 20% added cost
814818
let adjustedValue = ethToSend;
815-
if (chainId === 10) {
819+
if (chainId === 10 || chainId === 8453) {
816820
const costWithMargin = txCost.mul(100 + Math.min(retryCount, 20)).div(100);
817821
adjustedValue = adjustedValue.sub(costWithMargin);
818822
}

umbra-js/test/Umbra.test.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -156,54 +156,42 @@ describe('Umbra class', () => {
156156
expect(umbra3.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
157157
expect(umbra3.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
158158
expect(umbra3.chainConfig.startBlock).to.equal(3590825);
159-
expect(umbra3.chainConfig.subgraphUrl).to.equal(
160-
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-sepolia/v1.1.0/gn'
161-
);
162159

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

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

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

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

199184
// --- Arbitrum ---
200185
const umbra8 = new Umbra(jsonRpcProvider, 42161);
201186
expect(umbra8.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
202187
expect(umbra8.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
203188
expect(umbra8.chainConfig.startBlock).to.equal(7285883);
204-
expect(umbra8.chainConfig.subgraphUrl).to.equal(
205-
'https://api.goldsky.com/api/public/project_clfmn098ebuoc3svybn2l2tvp/subgraphs/umbra-arbitrum-one/v1.1.0/gn'
206-
);
189+
190+
// --- Base ---
191+
const umbra9 = new Umbra(jsonRpcProvider, 8453);
192+
expect(umbra9.chainConfig.umbraAddress).to.equal('0xFb2dc580Eed955B528407b4d36FfaFe3da685401');
193+
expect(umbra9.chainConfig.batchSendAddress).to.equal('0xDbD0f5EBAdA6632Dde7d47713ea200a7C2ff91EB');
194+
expect(umbra9.chainConfig.startBlock).to.equal(10761374);
207195
});
208196

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

0 commit comments

Comments
 (0)