Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { MixerSize } from '@webb-dapp/react-environment';

export class EvmChainStorage {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class should be renamed to EvmChainMixerInfo. This is because most of the fields inside of this class should not be dealing with storage.

constructor(
public contractsInfo: {
address: string;
size: number;
symbol: string;
syncedBlock: number;
leaves: string[];
}[]
) {}

get mixerSize(): MixerSize[] {
return this.contractsInfo.map((contract, index) => {
return {
id: contract.address,
title: `${contract.size} ${contract.symbol}`,
};
});
}
}
93 changes: 93 additions & 0 deletions packages/apps/src/configs/storages/evm-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { EvmChainStorage } from '@webb-dapp/apps/configs/storages/evm-chain-storage.interface';
import { StorageHandler } from '@webb-dapp/utils';
import { EVMStorage } from '@webb-dapp/react-environment/api-providers/web3';

const rinkebyStore = new EvmChainStorage([
{
size: 0.1,
address: '0x876eCe69618e8E8dd743250B036785813824D2D7',
symbol: 'ETH',
syncedBlock: 120000, // should be hardcoded to deployed block number
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't know what syncedBlock means. This should err on the side of being as verbose as needed. Is this the latest synced block? If so, lets call it, latestSyncedBlock or lastSyncedBlock or lastQueriedBlock, etc.

I think we should also add another parameter for createdAtBlock to indicate the block at which these mixers were created. This way, for new clients, we can begin fetching events immediately from the point they were created rather than before ever, mistakenly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the field can be named something more descriptive like lastQueriedBlock.

I think that these EvmChainStorage objects will be passed default values as params to the constructor. Therefore, the lastQueriedBlock can pass the deployed block number, and new clients will only ever start querying from the deployed block. In the constructor, we can read from the localStorage to determine if the client has anything in storage for the particular mixer.

leaves: [],
},
]);

const ethMainNet = new EvmChainStorage([
{
size: 0.1,
address: '0x876eCe69618e8E8dd743250B036785813824D2D7',
symbol: 'ETH',
syncedBlock: 1,
leaves: [],
},
]);

const beresheet = new EvmChainStorage([
{
size: 10,
address: '0x5f771fc87F87DB48C9fB11aA228D833226580689',
symbol: 'tEDG',
syncedBlock: 1,
leaves: [],
},
{
size: 100,
address: '0x2ee2e51cab1561E4482cacc8Be8b46CE61E46991',
symbol: 'tEDG',
syncedBlock: 1,
leaves: [],
},
{
size: 1000,
address: '0x5696b4AfBc169454d7FA26e0a41828d445CFae20',
symbol: 'tEDG',
syncedBlock: 1,
leaves: [],
},
{
size: 10000,
address: '0x626FEc5Ffa7Bf1EE8CEd7daBdE545630473E3ABb',
symbol: 'tEDG',
syncedBlock: 1,
leaves: [],
},
]);

const defaultHandler: Omit<StorageHandler<EVMStorage>, 'inner'> = {
async fetch(key: string) {
const data = localStorage.getItem(key);
if (!data) {
return {
nativeAnchor: new EvmChainStorage([]),
};
}
const address = JSON.parse(data).contractsAddresses;
Comment thread
drewstone marked this conversation as resolved.
return {
nativeAnchor: new EvmChainStorage(address),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this currently a nativeAnchor because the only mixers we currently have supported in the dApp are native? I suppose we'll want to plan accordingly for ERC20 supported mixers. Might be worth updating this now, thoughts?

};
},
async commit(key: string, data) {
localStorage.setItem(key, JSON.stringify(data.contractsAddresses));
},
};

export const rinkebyStorage: StorageHandler<EVMStorage> = {
...defaultHandler,
inner: {
nativeAnchor: rinkebyStore,
},
};

export const mainStorage: StorageHandler<EVMStorage> = {
...defaultHandler,
inner: {
nativeAnchor: ethMainNet,
},
};

export const beresheetStorage: StorageHandler<EVMStorage> = {
...defaultHandler,
inner: {
nativeAnchor: beresheet,
}
}
49 changes: 0 additions & 49 deletions packages/apps/src/configs/storages/rinkeby-storage.ts

This file was deleted.

62 changes: 49 additions & 13 deletions packages/contracts/src/contracts/anchor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@ export class AnchorContract {
return this._contract.nextIndex();
}

get denomination() {
return this._contract.denomination();
}

get inner() {
return this._contract;
}

async createDeposit(): Promise<{ note: EvmNote; deposit: Deposit }> {
async createDeposit(assetSymbol: string): Promise<{ note: EvmNote; deposit: Deposit }> {
const deposit = createDeposit();
const chainId = await this.signer.getChainId();
const note = new EvmNote('eth', 0.1, chainId, deposit.preimage);
const depositSizeBN = await this.denomination;
const depositSize = Number.parseFloat(utils.fromWei(depositSizeBN.toString(), "ether"));
const note = new EvmNote(assetSymbol, depositSize, chainId, deposit.preimage);
return {
note,
deposit,
Expand All @@ -48,8 +54,9 @@ export class AnchorContract {
const overrides = {
gasLimit: 6000000,
gasPrice: utils.toWei('1', 'gwei'),
value: '0x16345785D8A0000',
value: await this.denomination,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I don't know much about getters but why are we awaiting this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a call to the RPC to read the denomination from the contract deployed on the evm. We need to wait for the RPC response.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, so this is mostly to generalise over Substrate chains and EVM, since we get denomination info often asynchronously. Good stuff!

};
console.log(commitment);
const filters = await this._contract.filters.Deposit(commitment, null, null);
this._contract.once(filters, (commitment, insertedIndex, timestamp) => {
onComplete?.([commitment, insertedIndex, timestamp]);
Expand All @@ -60,17 +67,47 @@ export class AnchorContract {

private async getDepositEvents(commitment: string | null = null) {
const filter = this._contract.filters.Deposit(commitment, null, null);
const logs = await this.web3Provider.getLogs({
fromBlock: 0,
toBlock: 'latest',
...filter,
});
const currentBlock = await this.web3Provider.getBlockNumber();

// Look in the localStorage for this mixer (should be indexed under address)
// and get the syncedBlock / leaves that are present in the storage.
// Then query the blocks after the syncedBlock to update the leaves.

const startingBlock = 1; // Read starting block from cached storage, syncedBlock
var logs = []; // variable that holds newly fetched logs

try {
logs = await this.web3Provider.getLogs({
fromBlock: startingBlock,
toBlock: 'latest',
...filter,
});
} catch (e) {
console.log(e);

// If there is a timeout, query the logs in block increments.
if (e.code == -32603) {
for (var i=startingBlock; i < currentBlock; i+= 1000)
{
logs = [...logs, ...(await this.web3Provider.getLogs({
fromBlock: i,
toBlock: (currentBlock - i > 1000) ? i + 1000 : currentBlock,
...filter,
}))];
}
} else {
throw e;
}
}
console.log(logs);
return logs.map((log) => this._contract.interface.parseLog(log));
}

private async generateSnarkProof(deposit: Deposit) {
// const { path_elements, path_index, root } = await this.generateMerkleProof(deposit);
// After getting the events, we should parse out and sort the commitments (leaves) and
// append to the leaves localStorage for this mixer.
// Dynamically update the storage at _this.contract.address, querying the appropriate
// EVMChainStorage key of 'main', 'rinkeby', etc. using this.signer.getChainId() and
// WebbWeb3Provider.storageName(chainId);

return logs.map((log) => this._contract.interface.parseLog(log));
}

async generateMerkleProof(deposit: Deposit) {
Expand Down Expand Up @@ -105,7 +142,6 @@ export class AnchorContract {
let proving_key = require('../circuits/withdraw_proving_key.bin');
proving_key = await fetch(proving_key);
proving_key = await proving_key.arrayBuffer();
const bigInt = snarkjs.bigInt;

const input = {
// public
Expand Down
55 changes: 33 additions & 22 deletions packages/react-environment/src/WebbProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import WalletConnectProvider from '@walletconnect/web3-provider';
import { mainStorage, rankebyStorage } from '@webb-dapp/apps/configs/storages/rinkeby-storage';
import { beresheetStorage, mainStorage, rinkebyStorage } from '@webb-dapp/apps/configs/storages/rinkeby-storage';
import { chainsConfig } from '@webb-dapp/apps/configs/wallets/chain-config';
import { walletsConfig, WalletsIds } from '@webb-dapp/apps/configs/wallets/wallets-config';
import { EVMStorage, WebbEVMChain, WebbWeb3Provider } from '@webb-dapp/react-environment/api-providers/web3';
Expand Down Expand Up @@ -88,20 +88,27 @@ export const WebbProvider: FC<WebbProviderProps> = ({ applicationName = 'Webb Da
case WalletsIds.MetaMask:
{
const web3Provider = await Web3Provider.fromExtension();
const net = await web3Provider.netowrk;
const chainType = WebbWeb3Provider.chainType(net); // use this to pick the storage
const rainkybeS = await Storage.newFresh(WebbEVMChain.Rinkeby, rankebyStorage);
const mainS = await Storage.newFresh(WebbEVMChain.Main, mainStorage);
const net = await web3Provider.network; // storage based on network id
const chainType = WebbWeb3Provider.storageName(net);
// const rinkebyS = await Storage.newFresh(WebbEVMChain.Rinkeby, rinkebyStorage);
// const mainS = await Storage.newFresh(WebbEVMChain.Main, mainStorage);
// const beresheetS = await Storage.newFresh(WebbEVMChain.Beresheet, beresheetStorage);
let storage: Storage<EVMStorage>;
switch (chainType) {
switch (net) {
case WebbEVMChain.Main:
storage = mainS;
storage = await Storage.newFresh(chainType, mainStorage);
break;
case WebbEVMChain.Rinkeby:
storage = rainkybeS;
storage = await Storage.newFresh(chainType, rinkebyStorage);
break;
case WebbEVMChain.Beresheet:
storage = await Storage.newFresh(chainType, beresheetStorage);
break;
default:
storage = await Storage.newFresh(chainType, beresheetStorage);
break;
}
const webbWeb3Provider = await WebbWeb3Provider.init(web3Provider, rainkybeS);
const webbWeb3Provider = await WebbWeb3Provider.init(web3Provider, storage);
const accounts = await webbWeb3Provider.accounts.accounts();
setAccounts(accounts);
await setActiveAccount(accounts[0]);
Expand All @@ -121,20 +128,24 @@ export const WebbProvider: FC<WebbProviderProps> = ({ applicationName = 'Webb Da
});
const web3Provider = await Web3Provider.fromWalletConnectProvider(provider);
await web3Provider.eth.net.isListening();
const net = await web3Provider.netowrk;
const chainType = WebbWeb3Provider.chainType(net); // use this to pick the storage
const rainkybeS = await Storage.newFresh(WebbEVMChain.Rinkeby, rankebyStorage);
const mainS = await Storage.newFresh(WebbEVMChain.Main, mainStorage);
const net = await web3Provider.network; // storage based on network id
const chainType = WebbWeb3Provider.storageName(net);
let storage: Storage<EVMStorage>;
switch (chainType) {
case WebbEVMChain.Main:
storage = mainS;
break;
case WebbEVMChain.Rinkeby:
storage = rainkybeS;
break;
}
const webbWeb3Provider = await WebbWeb3Provider.init(web3Provider, rainkybeS);
switch (net) {
case WebbEVMChain.Main:
storage = await Storage.newFresh(chainType, mainStorage);
break;
case WebbEVMChain.Rinkeby:
storage = await Storage.newFresh(chainType, rinkebyStorage);
break;
case WebbEVMChain.Beresheet:
storage = await Storage.newFresh(chainType, beresheetStorage);
break;
default:
storage = await Storage.newFresh(chainType, beresheetStorage);
break;
}
const webbWeb3Provider = await WebbWeb3Provider.init(web3Provider, storage);

const accounts = await webbWeb3Provider.accounts.accounts();
setAccounts(accounts);
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,15 @@ export class Web3MixerDeposit extends MixerDeposit<WebbWeb3Provider, DepositPayl
async generateNote(mixerId: string, contractName: string = 'nativeAnchor'): Promise<DepositPayload> {
const contract = await this.inner.getContractWithAddress(mixerId);
const storages = await this.inner.chainStorage;
const mixerSize = storages[contractName].contractsAddresses.find((config) => config.address === mixerId);
if (!mixerSize) {
throw new Error(`mixer size not found on this contract`);
const mixerInfo = storages[contractName].contractsInfo.find((config) => config.address === mixerId);
if (!mixerInfo) {
throw new Error(`mixer not found from storage`);
}

const depositPayload = await contract.createDeposit();
console.log(depositPayload);
const depositPayload = await contract.createDeposit(mixerInfo.symbol);
return {
note: depositPayload.note,
params: [depositPayload.deposit, mixerSize.size],
params: [depositPayload.deposit, mixerInfo.size],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class Web3MixerWithdraw extends MixerWithdraw<WebbWeb3Provider> {
async withdraw(note: string, recipient: string, contractName: string = 'nativeAnchor'): Promise<void> {
this.emit('stateChange', WithdrawState.GeneratingZk);
const evmNote = EvmNote.deserialize(note);
const contarct = await this.inner.getContract(evmNote.amount, contractName);
const txReset = await contarct.withdraw(note, recipient);
const contract = await this.inner.getContract(evmNote.amount, contractName);
const txReset = await contract.withdraw(note, recipient);
transactionNotificationConfig.loading?.({
address: '',
data: undefined,
Expand Down
Loading