on master help sign in
fix: fix bridge
9791ce4pkova
package.json+9−7
@@ -83,13 +83,14 @@
83 "secure-ls": "^1.2.6",
83 "secure-ls": "^1.2.6",
84 "styled-components": "^5.3.0",
84 "styled-components": "^5.3.0",
85 "styled-system": "^5.1.5",
85 "styled-system": "^5.1.5",
86+ "truffle": "^5.11.4",
86 "typescript": "^4.3.2",
87 "typescript": "^4.3.2",
87 "urbit-key-generation": "^0.19.0",
88 "urbit-key-generation": "^0.19.0",
88 "urbit-ob": "^4.1.4",
89 "urbit-ob": "^4.1.4",
89 "urbit-paper-renderer": "^2.0.13",
90 "urbit-paper-renderer": "^2.0.13",
90− "web3": "^1.8.0",
91+ "web3": "^1.10.2",
91− "web3-core": "^1.8.0",
92+ "web3-core": "^1.10.2",
92− "web3-utils": "^1.8.0",
93+ "web3-utils": "^1.10.2",
93 "zustand": "^3.5.9"
94 "zustand": "^3.5.9"
94 },
95 },
95 "devDependencies": {
96 "devDependencies": {
@@ -109,7 +110,7 @@
109 "eslint-config-prettier": "^5.1.0",
110 "eslint-config-prettier": "^5.1.0",
110 "eslint-config-react-app": "^7.0.1",
111 "eslint-config-react-app": "^7.0.1",
111 "eslint-plugin-prettier": "^3.4.1",
112 "eslint-plugin-prettier": "^3.4.1",
112− "ganache-cli": "^6.2.1",
113+ "ganache": "^7.9.1",
113 "husky": "^2.4.0",
114 "husky": "^2.4.0",
114 "npm-run-all": "^4.1.3",
115 "npm-run-all": "^4.1.3",
115 "prettier": "^1.19.1",
116 "prettier": "^1.19.1",
@@ -124,7 +125,7 @@
124 },
125 },
125 "scripts": {
126 "scripts": {
126 "preview:mainnet": "VITE_MAINNET=true vite preview --port 3000",
127 "preview:mainnet": "VITE_MAINNET=true vite preview --port 3000",
127− "start": "vite",
128+ "start": "vite --clearScreen false",
128 "build": "VITE_MAINNET=true vite build",
129 "build": "VITE_MAINNET=true vite build",
129 "build:goerli": "VITE_GOERLI=true vite build",
130 "build:goerli": "VITE_GOERLI=true vite build",
130 "test": "echo 'TODO: set up vitest'",
131 "test": "echo 'TODO: set up vitest'",
@@ -132,7 +133,8 @@
132 "zip": "BRIDGE_VERSION=${VITE_BRIDGE_VERSION:-$npm_package_version}; zip -ur bridge-$BRIDGE_VERSION.zip README.md bridge-https.py checksums.txt && cd build && zip -ur ../bridge-$BRIDGE_VERSION.zip ./* && cd ..",
133 "zip": "BRIDGE_VERSION=${VITE_BRIDGE_VERSION:-$npm_package_version}; zip -ur bridge-$BRIDGE_VERSION.zip README.md bridge-https.py checksums.txt && cd build && zip -ur ../bridge-$BRIDGE_VERSION.zip ./* && cd ..",
133 "release": "npm install && npm run build && npm run checksum && npm run zip",
134 "release": "npm install && npm run build && npm run checksum && npm run zip",
134 "release:goerli": "export VITE_BRIDGE_VERSION=$npm_package_version\"r\"; npm install && npm run build:goerli && npm run checksum && npm run zip",
135 "release:goerli": "export VITE_BRIDGE_VERSION=$npm_package_version\"r\"; npm install && npm run build:goerli && npm run checksum && npm run zip",
135− "pilot:ganache": "ganache-cli --blockTime 1 --networkId 5 --host '0.0.0.0' -m 'benefit crew supreme gesture quantum web media hazard theory mercy wing kitten' > /dev/null &",
136+ "pilot:ganache": "ganache --blockTime 1 --chain.chainId=1337 --chain.networkId=5 --chain.hardfork=merge --host '0.0.0.0' -m 'benefit crew supreme gesture quantum web media hazard theory mercy wing kitten' > /dev/null &",
137+ "pilot:truffle": "truffle deploy",
136 "pilot:setup": "npm run pilot:ganache && truffle deploy",
138 "pilot:setup": "npm run pilot:ganache && truffle deploy",
137 "pilot": "HTTPS=true npm-run-all pilot:setup start pilot:cleanup --continue-on-error",
139 "pilot": "HTTPS=true npm-run-all pilot:setup start pilot:cleanup --continue-on-error",
138 "pilot-invites": "WITH_TEST_STATE=INVITES npm run pilot",
140 "pilot-invites": "WITH_TEST_STATE=INVITES npm run pilot",
@@ -142,7 +144,7 @@
142 "pilot-l2": "BROWSER=NONE WITH_TEST_STATE=L2 HTTPS=false NODE_ENV=development npm-run-all pilot:setup start pilot:cleanup --continue-on-error",
144 "pilot-l2": "BROWSER=NONE WITH_TEST_STATE=L2 HTTPS=false NODE_ENV=development npm-run-all pilot:setup start pilot:cleanup --continue-on-error",
143 "pilot-l2-local": "BROWSER=NONE VITE_L2=true HTTPS=false NODE_ENV=development npm run start --continue-on-error",
145 "pilot-l2-local": "BROWSER=NONE VITE_L2=true HTTPS=false NODE_ENV=development npm run start --continue-on-error",
144 "pilot-goerli": "VITE_GOERLI=true HTTPS=true npm-run-all start --continue-on-error",
146 "pilot-goerli": "VITE_GOERLI=true HTTPS=true npm-run-all start --continue-on-error",
145− "pilot:cleanup": "pkill -f ganache-cli",
147+ "pilot:cleanup": "pkill -f ganache",
146 "lint:check": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
148 "lint:check": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
147 "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
149 "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
148 "analyze": "source-map-explorer 'build/static/js/*.js'"
150 "analyze": "source-map-explorer 'build/static/js/*.js'"
src/lib/reticket.js+3
@@ -172,6 +172,7 @@ export async function reticketPointBetweenWallets({
172 gasLimit: txs[i].gas,
172 gasLimit: txs[i].gas,
173 txnSigner,
173 txnSigner,
174 txnSender,
174 txnSender,
175+ web3,
175 });
176 });
176 txPairs.push({
177 txPairs.push({
177 raw: hexify(stx.serialize()),
178 raw: hexify(stx.serialize()),
@@ -242,6 +243,7 @@ export async function reticketPointBetweenWallets({
242 gasPriceData,
243 gasPriceData,
243 gasLimit,
244 gasLimit,
244 nonce: inviteNonce,
245 nonce: inviteNonce,
246+ web3,
245 });
247 });
246 sendSignedTransaction(web3, stx);
248 sendSignedTransaction(web3, stx);
247
249
@@ -272,6 +274,7 @@ export async function reticketPointBetweenWallets({
272 gasPriceData,
274 gasPriceData,
273 gasLimit,
275 gasLimit,
274 nonce: inviteNonce,
276 nonce: inviteNonce,
277+ web3,
275 });
278 });
276 sendSignedTransaction(web3, stx);
279 sendSignedTransaction(web3, stx);
277 } catch (err) {
280 } catch (err) {
src/lib/txn.ts+19−18
@@ -60,17 +60,10 @@ interface signTransactionProps {
60 gasLimit: number;
60 gasLimit: number;
61 txnSigner?: (args: ITxData) => Promise<string>;
61 txnSigner?: (args: ITxData) => Promise<string>;
62 txnSender?: (args: ITxData) => Promise<string>;
62 txnSender?: (args: ITxData) => Promise<string>;
63+ web3: Web3;
63}
64}
64
65
65−const _web3 = () => {
66− const ENDPOINT = `https://mainnet.infura.io/v3/${
67− import.meta.env.VITE_INFURA_ENDPOINT
68− }`;
69− return new Web3(new Web3.providers.HttpProvider(ENDPOINT));
70−};
71−
72−const estimateGasLimit = async (utx: TransactionConfig) => {
66+const estimateGasLimit = async (utx: TransactionConfig, web3: Web3) => {
73− const web3 = _web3();
74 const estimate = await web3.eth.estimateGas(utx);
67 const estimate = await web3.eth.estimateGas(utx);
75 return web3.utils
68 return web3.utils
76 .toBN(estimate)
69 .toBN(estimate)
@@ -78,8 +71,7 @@ const estimateGasLimit = async (utx: TransactionConfig) => {
78 .divn(100); // 20% cushion
71 .divn(100); // 20% cushion
79};
72};
80
73
81−const getMaxFeePerGas = async () => {
74+const getMaxFeePerGas = async (web3: Web3) => {
82− const web3 = _web3();
83 const fee = await web3.eth.getGasPrice();
75 const fee = await web3.eth.getGasPrice();
84 return (Number(fee) * 1.2).toFixed(0); // 20% cushion
76 return (Number(fee) * 1.2).toFixed(0); // 20% cushion
85};
77};
@@ -96,10 +88,11 @@ const signTransaction = async ({
96 gasLimit, // TODO: do we need the default values anymore? now that the estiamte is loaded dynamically
88 gasLimit, // TODO: do we need the default values anymore? now that the estiamte is loaded dynamically
97 txnSigner, // optionally inject a transaction signing function,
89 txnSigner, // optionally inject a transaction signing function,
98 txnSender, // and a sending function, for wallets that need these passed in.
90 txnSender, // and a sending function, for wallets that need these passed in.
91+ web3,
99}: signTransactionProps) => {
92}: signTransactionProps) => {
100 const from = wallet.address;
93 const from = wallet.address;
101− const estimate = await estimateGasLimit({ ...txn, from });
94+ const estimate = await estimateGasLimit({ ...txn, from }, web3);
102− const maxFeePerGas = await getMaxFeePerGas();
95+ const maxFeePerGas = await getMaxFeePerGas(web3);
103
96
104 const txParams: EIP1559TxData = {
97 const txParams: EIP1559TxData = {
105 data: toHex(txn.data),
98 data: toHex(txn.data),
@@ -115,14 +108,22 @@ const signTransaction = async ({
115 };
108 };
116
109
117 const chain =
110 const chain =
118− networkType === NETWORK_TYPES.GOERLI ? Chain.Goerli : Chain.Mainnet;
111+ (networkType === NETWORK_TYPES.GOERLI) ||
112+ (networkType === NETWORK_TYPES.LOCAL) ? Chain.Goerli : Chain.Mainnet;
113+
114+ const common = new Common({
115+ chain,
116+ hardfork: Hardfork.Merge,
117+ });
118+
119+ if (networkType === NETWORK_TYPES.LOCAL) {
120+ common._chainParams.chainId = 1337;
121+ common._chainParams.name = "ganache";
122+ }
119
123
120 const txConfig: TxOptions = {
124 const txConfig: TxOptions = {
121 freeze: false,
125 freeze: false,
122− common: new Common({
126+ common: common,
123− chain,
124− hardfork: Hardfork.Merge,
125− }),
126 };
127 };
127
128
128 let stx = EIP1559Transaction.fromTxData(txParams, txConfig);
129 let stx = EIP1559Transaction.fromTxData(txParams, txConfig);
src/lib/useEthereumTransaction.js+2−2
@@ -139,6 +139,7 @@ export default function useEthereumTransaction(
139 gasLimit,
139 gasLimit,
140 txnSigner,
140 txnSigner,
141 txnSender,
141 txnSender,
142+ web3: _web3,
142 })
143 })
143 )
144 )
144 );
145 );
@@ -281,13 +282,12 @@ export default function useEthereumTransaction(
281 setError(undefined);
282 setError(undefined);
282 const [nonce, chainId] = await Promise.all([
283 const [nonce, chainId] = await Promise.all([
283 _web3.eth.getTransactionCount(_wallet.address),
284 _web3.eth.getTransactionCount(_wallet.address),
284− _web3.eth.net.getId(),
285+ _web3.eth.getChainId(),
285 ]);
286 ]);
286
287
287 if (!mounted) {
288 if (!mounted) {
288 return;
289 return;
289 }
290 }
290−
291 setNonce(nonce);
291 setNonce(nonce);
292 setChainId(chainId);
292 setChainId(chainId);
293 } catch (error) {
293 } catch (error) {
src/lib/useRoller.ts+20−20
@@ -145,35 +145,35 @@ export default function useRoller() {
145 }
145 }
146
146
147 const pointNum = Number(point);
147 const pointNum = Number(point);
148+ const rawDetails = await api.getPoint(pointNum);
149+ const isL2 = isL2Spawn(rawDetails?.dominion);
150+
148 try {
151 try {
149− const rawDetails = await api.getPoint(pointNum);
152+ if (isL2) {
150− const isL2 = isL2Spawn(rawDetails?.dominion);
151− const l2Quota = isL2 ? await api.getRemainingQuota(pointNum) : 0;
153+ const l2Quota = isL2 ? await api.getRemainingQuota(pointNum) : 0;
152− const l2Allowance = isL2 ? await api.getAllowance(pointNum) : 0;
154+ const l2Allowance = isL2 ? await api.getAllowance(pointNum) : 0;
153
155
154− const details = toL1Details(rawDetails);
156+ const details = toL1Details(rawDetails);
155
157
158+ return new Point({
159+ value: pointNum,
160+ details,
161+ address: _wallet.address,
162+ l2Quota,
163+ l2Allowance,
164+ });
165+ }
166+
167+ const _contracts = need.contracts(contracts);
168+ const details = await azimuth.azimuth.getPoint(_contracts, point);
156 return new Point({
169 return new Point({
157 value: pointNum,
170 value: pointNum,
158 details,
171 details,
159 address: _wallet.address,
172 address: _wallet.address,
160− l2Quota,
161− l2Allowance,
162 });
173 });
174+
163 } catch (e) {
175 } catch (e) {
164 console.warn(e);
176 console.warn(e);
165−
166− // Try getting the details from L1
167− try {
168− const _contracts = need.contracts(contracts);
169− const details = await azimuth.azimuth.getPoint(_contracts, point);
170− return new Point({
171− value: pointNum,
172− details,
173− address: _wallet.address,
174− });
175− } catch (e) {
176− console.warn(e);
177 // Just return a placeholder Point
177 // Just return a placeholder Point
178 const details: L1Point = toL1Details();
178 const details: L1Point = toL1Details();
179 return new Point({
179 return new Point({
@@ -182,7 +182,7 @@ export default function useRoller() {
182 address: _wallet.address,
182 address: _wallet.address,
183 isPlaceholder: true,
183 isPlaceholder: true,
184 });
184 });
185− }
185+
186 }
186 }
187 },
187 },
188 [api, wallet, contracts]
188 [api, wallet, contracts]
src/store/network.jsx−14
@@ -25,20 +25,6 @@ function _useNetwork(initialNetworkType = null) {
25 const [web3, setWeb3] = useState(Nothing());
25 const [web3, setWeb3] = useState(Nothing());
26 const [contracts, setContracts] = useState(Nothing());
26 const [contracts, setContracts] = useState(Nothing());
27
27
28− useEffect(() => {
29− (async () => {
30− const provider = await detectEthereumProvider();
31− if (provider) {
32− try {
33− setMetamask(true);
34− setNetworkType(chainIdToNetworkType(window.ethereum.chainId));
35− } catch (e) {
36− console.log('Metamask denied');
37− }
38− }
39− })();
40− }, []);
41−
42 useEffect(() => {
28 useEffect(() => {
43 (async () => {
29 (async () => {
44 // given a web3 provider and contract addresses,
30 // given a web3 provider and contract addresses,
src/views/Login/LoginSelector.tsx+12−1
@@ -18,7 +18,7 @@ import { useHistory } from 'store/history';
18import { useWallet } from 'store/wallet';
18import { useWallet } from 'store/wallet';
19import { useNetwork } from 'store/network';
19import { useNetwork } from 'store/network';
20
20
21−import { WALLET_TYPES } from 'lib/constants';
21+import { WALLET_TYPES, ETHEREUM_LOCAL_CHAIN_ID } from 'lib/constants';
22import { useWalletConnect } from 'lib/useWalletConnect';
22import { useWalletConnect } from 'lib/useWalletConnect';
23import { MetamaskWallet } from 'lib/metamask';
23import { MetamaskWallet } from 'lib/metamask';
24import { expectedChainId } from 'lib/network';
24import { expectedChainId } from 'lib/network';
@@ -101,6 +101,17 @@ export default function LoginSelector({
101 */
101 */
102 if (window.ethereum.chainId !== expectedChainId()) {
102 if (window.ethereum.chainId !== expectedChainId()) {
103 console.log(`unexpected chain: ${window.ethereum.chainId}`);
103 console.log(`unexpected chain: ${window.ethereum.chainId}`);
104+
105+ if (expectedChainId() === ETHEREUM_LOCAL_CHAIN_ID) {
106+ await window.ethereum.request({
107+ method: "wallet_addEthereumChain",
108+ params: [{chainId: ETHEREUM_LOCAL_CHAIN_ID,
109+ chainName: "Ganache",
110+ rpcUrls: ["http://127.0.0.1:8545"]
111+ }]
112+ });
113+ }
114+
104 await window.ethereum.request({
115 await window.ethereum.request({
105 method: 'wallet_switchEthereumChain',
116 method: 'wallet_switchEthereumChain',
106 params: [{ chainId: expectedChainId() }],
117 params: [{ chainId: expectedChainId() }],
src/views/Login/Mnemonic.tsx+14−29
@@ -25,7 +25,6 @@ import HeaderPane from 'components/L2/Window/HeaderPane';
25import BodyPane from 'components/L2/Window/BodyPane';
25import BodyPane from 'components/L2/Window/BodyPane';
26import AdvancedOptions from 'components/L2/Headers/AdvancedOptions';
26import AdvancedOptions from 'components/L2/Headers/AdvancedOptions';
27import { Row } from '@tlon/indigo-react';
27import { Row } from '@tlon/indigo-react';
28−import { debounce } from 'lodash';
29
28
30interface MnemonicProps {
29interface MnemonicProps {
31 className?: string;
30 className?: string;
@@ -35,6 +34,19 @@ interface MnemonicProps {
35export default function Mnemonic({ className, goHome }: MnemonicProps) {
34export default function Mnemonic({ className, goHome }: MnemonicProps) {
36 useLoginView(WALLET_TYPES.MNEMONIC);
35 useLoginView(WALLET_TYPES.MNEMONIC);
37
36
37+ const onSubmit = (values, valid) => {
38+ setWalletHdPath(values.hdpath);
39+ setAuthMnemonic(Just(values.mnemonic));
40+ setWallet(
41+ walletFromMnemonic(
42+ values.mnemonic,
43+ values.hdpath,
44+ values.passphrase,
45+ skipValidation
46+ )
47+ );
48+ };
49+
38 const {
50 const {
39 setWallet,
51 setWallet,
40 setAuthMnemonic,
52 setAuthMnemonic,
@@ -58,33 +70,6 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
58 });
70 });
59 }, [skipValidation]);
71 }, [skipValidation]);
60
72
61− // when the properties change, re-derive wallet and set global state
62− const debouncedOnValues = debounce(({ valid, values }) => {
63− if (valid) {
64− setWalletHdPath(values.hdpath);
65− setAuthMnemonic(Just(values.mnemonic));
66− setWallet(
67− walletFromMnemonic(
68− values.mnemonic,
69− values.hdpath,
70− values.passphrase,
71− skipValidation
72− )
73− );
74− } else {
75− setAuthMnemonic(Nothing());
76− setWallet(Nothing());
77− }
78− }, ONE_SECOND);
79−
80− const onValues = useCallback(debouncedOnValues, [
81− setAuthMnemonic,
82− setWallet,
83− setWalletHdPath,
84− skipValidation,
85− debouncedOnValues,
86− ]);
87−
88 const initialValues = {
73 const initialValues = {
89 hdpath: DEFAULT_HD_PATH,
74 hdpath: DEFAULT_HD_PATH,
90 useAdvanced: false,
75 useAdvanced: false,
@@ -123,7 +108,7 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
123 <Grid className={cn(className, 'input-form')}>
108 <Grid className={cn(className, 'input-form')}>
124 <BridgeForm
109 <BridgeForm
125 validate={validate}
110 validate={validate}
126− onValues={onValues}
111+ onSubmit={onSubmit}
127 afterSubmit={goHome}
112 afterSubmit={goHome}
128 initialValues={initialValues}>
113 initialValues={initialValues}>
129 {({ handleSubmit }: any) => (
114 {({ handleSubmit }: any) => (
src/views/Points.tsx+18−1
@@ -65,6 +65,7 @@ function ActionButtons({ actions = [] }: ActionButtonProps) {
65
65
66export default function Points() {
66export default function Points() {
67 const { wallet }: any = useWallet();
67 const { wallet }: any = useWallet();
68+ const { web3 }: any = useNetwork();
68 const { pop, push, names }: any = useHistory();
69 const { pop, push, names }: any = useHistory();
69 const { setPointCursor }: any = usePointCursor();
70 const { setPointCursor }: any = usePointCursor();
70 const { controlledPoints, getDetails }: any = usePointCache();
71 const { controlledPoints, getDetails }: any = usePointCache();
@@ -74,12 +75,28 @@ export default function Points() {
74 rejectedPoints,
75 rejectedPoints,
75 addRejectedPoint,
76 addRejectedPoint,
76 ] = useRejectedIncomingPointTransfers();
77 ] = useRejectedIncomingPointTransfers();
77− const { pointList } = useRollerStore();
78+ const { pointList, setEthBalance } = useRollerStore();
78 const {
79 const {
79 syncStarReleaseDetails,
80 syncStarReleaseDetails,
80 starReleaseDetails,
81 starReleaseDetails,
81 }: any = useStarReleaseCache();
82 }: any = useStarReleaseCache();
82
83
84+ useEffect(() => {
85+ const getEthBalance = async () => {
86+ const _web3 = web3.getOrElse(null);
87+ const _wallet = wallet.getOrElse(null);
88+
89+ if (_web3 && _wallet) {
90+ const newBalance = _web3.utils.fromWei(
91+ await _web3.eth.getBalance(_wallet.address)
92+ );
93+ setEthBalance(newBalance);
94+ }
95+ };
96+
97+ getEthBalance();
98+ }, [setEthBalance, wallet, web3]);
99+
83 const outgoingPoints = useMemo(
100 const outgoingPoints = useMemo(
84 () => pointList.filter(({ isOutgoing }) => isOutgoing),
101 () => pointList.filter(({ isOutgoing }) => isOutgoing),
85 [pointList]
102 [pointList]