From 5187120fa02acbc6105e3dc97fe1e203607b6970 Mon Sep 17 00:00:00 2001
From: Evan Gray <56235822+evan-gray@users.noreply.github.com>
Date: Wed, 4 Aug 2021 12:08:46 -0400
Subject: [PATCH] bridge_ui: eth wrapped assets and getSignedVAA
Change-Id: I1beaeefb7863c0543e180ed2e15e91c645b89299
---
bridge_ui/package-lock.json | 21 +---
bridge_ui/package.json | 1 +
bridge_ui/src/components/Transfer.tsx | 118 +++++++++++++++-------
bridge_ui/src/hooks/useEthereumBalance.ts | 2 -
bridge_ui/src/hooks/useWrappedAsset.ts | 41 ++++++++
bridge_ui/src/muiTheme.js | 2 +-
bridge_ui/src/sdk/index.ts | 34 +++++++
bridge_ui/src/utils/consts.ts | 15 ++-
bridge_ui/src/utils/transferFrom.ts | 97 ++++++++++--------
bridge_ui/src/utils/wrappedAsset.ts | 24 +++++
bridge_ui/tsconfig.json | 1 +
buf.gen.web.yaml | 2 +-
tools/package-lock.json | 14 +--
tools/package.json | 5 +-
14 files changed, 269 insertions(+), 108 deletions(-)
create mode 100644 bridge_ui/src/hooks/useWrappedAsset.ts
create mode 100644 bridge_ui/src/sdk/index.ts
create mode 100644 bridge_ui/src/utils/wrappedAsset.ts
diff --git a/bridge_ui/package-lock.json b/bridge_ui/package-lock.json
index 872264967..c328bbf12 100644
--- a/bridge_ui/package-lock.json
+++ b/bridge_ui/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.1.0",
"hasInstallScript": true,
"dependencies": {
+ "@improbable-eng/grpc-web": "^0.13.0",
"@material-ui/core": "^4.12.2",
"@metamask/detect-provider": "^1.2.0",
"@project-serum/sol-wallet-adapter": "^0.2.5",
@@ -4011,8 +4012,6 @@
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.13.0.tgz",
"integrity": "sha512-vaxxT+Qwb7GPqDQrBV4vAAfH0HywgOLw6xGIKXd9Q8hcV63CQhmS3p4+pZ9/wVvt4Ph3ZDK9fdC983b9aGMUFg==",
- "dev": true,
- "optional": true,
"dependencies": {
"browser-headers": "^0.4.0"
},
@@ -10309,9 +10308,7 @@
"node_modules/browser-headers": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz",
- "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==",
- "dev": true,
- "optional": true
+ "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg=="
},
"node_modules/browser-process-hrtime": {
"version": "1.0.0",
@@ -17417,9 +17414,7 @@
"node_modules/google-protobuf": {
"version": "3.17.3",
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.17.3.tgz",
- "integrity": "sha512-OVPzcSWIAJ+d5yiHyeaLrdufQtrvaBrF4JQg+z8ynTkbO3uFcujqXszTumqg1cGsAsjkWnI+M5B1xZ19yR4Wyg==",
- "dev": true,
- "optional": true
+ "integrity": "sha512-OVPzcSWIAJ+d5yiHyeaLrdufQtrvaBrF4JQg+z8ynTkbO3uFcujqXszTumqg1cGsAsjkWnI+M5B1xZ19yR4Wyg=="
},
"node_modules/got": {
"version": "9.6.0",
@@ -41493,8 +41488,6 @@
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.13.0.tgz",
"integrity": "sha512-vaxxT+Qwb7GPqDQrBV4vAAfH0HywgOLw6xGIKXd9Q8hcV63CQhmS3p4+pZ9/wVvt4Ph3ZDK9fdC983b9aGMUFg==",
- "dev": true,
- "optional": true,
"requires": {
"browser-headers": "^0.4.0"
}
@@ -46695,9 +46688,7 @@
"browser-headers": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz",
- "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==",
- "dev": true,
- "optional": true
+ "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg=="
},
"browser-process-hrtime": {
"version": "1.0.0",
@@ -52508,9 +52499,7 @@
"google-protobuf": {
"version": "3.17.3",
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.17.3.tgz",
- "integrity": "sha512-OVPzcSWIAJ+d5yiHyeaLrdufQtrvaBrF4JQg+z8ynTkbO3uFcujqXszTumqg1cGsAsjkWnI+M5B1xZ19yR4Wyg==",
- "dev": true,
- "optional": true
+ "integrity": "sha512-OVPzcSWIAJ+d5yiHyeaLrdufQtrvaBrF4JQg+z8ynTkbO3uFcujqXszTumqg1cGsAsjkWnI+M5B1xZ19yR4Wyg=="
},
"got": {
"version": "9.6.0",
diff --git a/bridge_ui/package.json b/bridge_ui/package.json
index ccadaf631..4888dc496 100644
--- a/bridge_ui/package.json
+++ b/bridge_ui/package.json
@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@improbable-eng/grpc-web": "^0.13.0",
"@material-ui/core": "^4.12.2",
"@metamask/detect-provider": "^1.2.0",
"@project-serum/sol-wallet-adapter": "^0.2.5",
diff --git a/bridge_ui/src/components/Transfer.tsx b/bridge_ui/src/components/Transfer.tsx
index ac9986737..55ccba2c8 100644
--- a/bridge_ui/src/components/Transfer.tsx
+++ b/bridge_ui/src/components/Transfer.tsx
@@ -1,5 +1,6 @@
import {
Button,
+ CircularProgress,
Grid,
makeStyles,
MenuItem,
@@ -11,6 +12,7 @@ import { useEthereumProvider } from "../contexts/EthereumProviderContext";
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
import useEthereumBalance from "../hooks/useEthereumBalance";
import useSolanaBalance from "../hooks/useSolanaBalance";
+import useWrappedAsset from "../hooks/useWrappedAsset";
import {
ChainId,
CHAINS,
@@ -105,8 +107,18 @@ function Transfer() {
decimals: solDecimals,
uiAmount: solBalance,
} = useSolanaBalance(assetAddress, solPK, fromChain === CHAIN_ID_SOLANA);
+ const { isLoading: isCheckingWrapped, wrappedAsset } = useWrappedAsset(
+ toChain,
+ fromChain,
+ assetAddress,
+ provider
+ );
+ console.log(isCheckingWrapped, wrappedAsset);
+ // TODO: make a helper function for this
+ const isWrapped = true;
+ //wrappedAsset && wrappedAsset !== ethers.constants.AddressZero;
// TODO: dynamically get "to" wallet
- const handleClick = useCallback(() => {
+ const handleTransferClick = useCallback(() => {
// TODO: more generic way of calling these
if (transferFrom[fromChain]) {
if (
@@ -210,39 +222,77 @@ function Transfer() {
value={assetAddress}
onChange={handleAssetChange}
/>
-
-
- {canAttemptTransfer ? null : (
-
- {!isTransferImplemented
- ? `Transfer is not yet implemented for ${CHAINS_BY_ID[fromChain].name}`
- : !isProviderConnected
- ? "The source wallet is not connected"
- : !isRecipientAvailable
- ? "The receiving wallet is not connected"
- : !isAddressDefined
- ? "Please provide an asset address"
- : !isAmountPositive
- ? "The amount must be positive"
- : !isBalanceAtLeastAmount
- ? "The amount may not be greater than the balance"
- : ""}
-
+ {isWrapped ? (
+ <>
+
+
+ {canAttemptTransfer ? null : (
+
+ {!isTransferImplemented
+ ? `Transfer is not yet implemented for ${CHAINS_BY_ID[fromChain].name}`
+ : !isProviderConnected
+ ? "The source wallet is not connected"
+ : !isRecipientAvailable
+ ? "The receiving wallet is not connected"
+ : !isAddressDefined
+ ? "Please provide an asset address"
+ : !isAmountPositive
+ ? "The amount must be positive"
+ : !isBalanceAtLeastAmount
+ ? "The amount may not be greater than the balance"
+ : ""}
+
+ )}
+ >
+ ) : (
+ <>
+
+
+ {isCheckingWrapped ? (
+
+ ) : null}
+
+ {isCheckingWrapped ? null : (
+
+
+ This token does not exist on {CHAINS_BY_ID[toChain].name}. Someone
+ must attest the the token to the target chain before it can be
+ transferred.
+
+ )}
+ >
)}
);
diff --git a/bridge_ui/src/hooks/useEthereumBalance.ts b/bridge_ui/src/hooks/useEthereumBalance.ts
index 1e48cea8a..8b3edcf0c 100644
--- a/bridge_ui/src/hooks/useEthereumBalance.ts
+++ b/bridge_ui/src/hooks/useEthereumBalance.ts
@@ -20,12 +20,10 @@ function useEthereumBalance(
token
.decimals()
.then((decimals) => {
- console.log(decimals);
provider
?.getSigner()
.getAddress()
.then((pk) => {
- console.log(pk);
token.balanceOf(pk).then((n) => {
if (!cancelled) {
setBalance(formatUnits(n, decimals));
diff --git a/bridge_ui/src/hooks/useWrappedAsset.ts b/bridge_ui/src/hooks/useWrappedAsset.ts
new file mode 100644
index 000000000..a46095a07
--- /dev/null
+++ b/bridge_ui/src/hooks/useWrappedAsset.ts
@@ -0,0 +1,41 @@
+import { ethers } from "ethers";
+import { useEffect, useState } from "react";
+import { ChainId, CHAIN_ID_ETH } from "../utils/consts";
+import { wrappedAssetEth } from "../utils/wrappedAsset";
+
+export interface WrappedAssetState {
+ isLoading: boolean;
+ wrappedAsset: string | null;
+}
+
+function useWrappedAsset(
+ checkChain: ChainId,
+ originChain: ChainId,
+ originAsset: string,
+ provider: ethers.providers.Web3Provider | undefined
+) {
+ const [state, setState] = useState({
+ isLoading: false,
+ wrappedAsset: null,
+ });
+ useEffect(() => {
+ let cancelled = false;
+ (async () => {
+ if (provider && checkChain === CHAIN_ID_ETH) {
+ setState({ isLoading: true, wrappedAsset: null });
+ const asset = await wrappedAssetEth(provider, originChain, originAsset);
+ if (!cancelled) {
+ setState({ isLoading: false, wrappedAsset: asset });
+ }
+ } else {
+ setState({ isLoading: false, wrappedAsset: null });
+ }
+ })();
+ return () => {
+ cancelled = true;
+ };
+ }, [checkChain, originChain, originAsset, provider]);
+ return state;
+}
+
+export default useWrappedAsset;
diff --git a/bridge_ui/src/muiTheme.js b/bridge_ui/src/muiTheme.js
index cb992c062..b750d800f 100644
--- a/bridge_ui/src/muiTheme.js
+++ b/bridge_ui/src/muiTheme.js
@@ -8,7 +8,7 @@ export const theme = responsiveFontSizes(
default: "#010114",
paper: "#010114",
},
- divider: "#FFFFFF",
+ divider: "#4e4e54",
primary: {
main: "#0074FF",
},
diff --git a/bridge_ui/src/sdk/index.ts b/bridge_ui/src/sdk/index.ts
new file mode 100644
index 000000000..f989e236a
--- /dev/null
+++ b/bridge_ui/src/sdk/index.ts
@@ -0,0 +1,34 @@
+import {
+ GrpcWebImpl,
+ PublicrpcClientImpl,
+} from "../proto/publicrpc/v1/publicrpc";
+import { ChainId } from "../utils/consts";
+
+export async function getSignedVAA(
+ emitterChain: ChainId,
+ emitterAddress: string,
+ sequence: string
+) {
+ const rpc = new GrpcWebImpl("http://localhost:8080", {});
+ const api = new PublicrpcClientImpl(rpc);
+ // TODO: potential infinite loop, support cancellation?
+ let result;
+ while (!result) {
+ console.log("wait 1 second");
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ console.log("check for signed vaa", emitterChain, emitterAddress, sequence);
+ try {
+ result = await api.GetSignedVAA({
+ messageId: {
+ emitterChain,
+ emitterAddress,
+ sequence,
+ },
+ });
+ console.log(result);
+ } catch (e) {
+ console.log(e);
+ }
+ }
+ return result;
+}
diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts
index 771049aba..8050b0f53 100644
--- a/bridge_ui/src/utils/consts.ts
+++ b/bridge_ui/src/utils/consts.ts
@@ -1,3 +1,5 @@
+import { getAddress } from "ethers/lib/utils";
+
export type ChainId = 1 | 2 | 3 | 4;
export const CHAIN_ID_SOLANA: ChainId = 1;
export const CHAIN_ID_ETH: ChainId = 2;
@@ -31,10 +33,15 @@ export const CHAINS_BY_ID: ChainsById = CHAINS.reduce((obj, chain) => {
return obj;
}, {} as ChainsById);
export const SOLANA_HOST = "http://localhost:8899";
-export const ETH_TEST_TOKEN_ADDRESS =
- "0x0290FB167208Af455bB137780163b7B7a9a10C16";
-export const ETH_TOKEN_BRIDGE_ADDRESS =
- "0xe982e462b094850f12af94d21d470e21be9d0e9c";
+export const ETH_TEST_TOKEN_ADDRESS = getAddress(
+ "0x0290FB167208Af455bB137780163b7B7a9a10C16"
+);
+export const ETH_BRIDGE_ADDRESS = getAddress(
+ "0x254dffcd3277c0b1660f6d42efbb754edababc2b"
+);
+export const ETH_TOKEN_BRIDGE_ADDRESS = getAddress(
+ "0xe982e462b094850f12af94d21d470e21be9d0e9c"
+);
export const SOL_TEST_TOKEN_ADDRESS =
"2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ";
export const SOL_BRIDGE_ADDRESS = "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o";
diff --git a/bridge_ui/src/utils/transferFrom.ts b/bridge_ui/src/utils/transferFrom.ts
index 9bde64178..70f1795e1 100644
--- a/bridge_ui/src/utils/transferFrom.ts
+++ b/bridge_ui/src/utils/transferFrom.ts
@@ -1,4 +1,5 @@
import Wallet from "@project-serum/sol-wallet-adapter";
+import { Token, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import {
AccountMeta,
Connection,
@@ -7,17 +8,19 @@ import {
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
-import { Token, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { ethers } from "ethers";
import { arrayify, formatUnits, parseUnits, zeroPad } from "ethers/lib/utils";
import {
Bridge__factory,
+ Implementation__factory,
TokenImplementation__factory,
} from "../ethers-contracts";
+import { getSignedVAA } from "../sdk";
import {
ChainId,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
+ ETH_BRIDGE_ADDRESS,
ETH_TOKEN_BRIDGE_ADDRESS,
SOLANA_HOST,
SOL_BRIDGE_ADDRESS,
@@ -41,46 +44,60 @@ export function transferFromEth(
//TODO: don't hardcode, fetch decimals / share them with balance, how do we determine recipient chain?
//TODO: more catches
const amountParsed = parseUnits(amount, 18);
- signer.getAddress().then((signerAddress) => {
+ (async () => {
+ const signerAddress = await signer.getAddress();
console.log("Signer:", signerAddress);
console.log("Token:", tokenAddress);
const token = TokenImplementation__factory.connect(tokenAddress, signer);
- token
- .allowance(signerAddress, ETH_TOKEN_BRIDGE_ADDRESS)
- .then((allowance) => {
- console.log("Allowance", allowance.toString()); //TODO: should we check that this is zero and warn if it isn't?
- token
- .approve(ETH_TOKEN_BRIDGE_ADDRESS, amountParsed)
- .then((transaction) => {
- console.log(transaction);
- const fee = 0; // for now, this won't do anything, we may add later
- const nonceConst = Math.random() * 100000;
- const nonceBuffer = Buffer.alloc(4);
- nonceBuffer.writeUInt32LE(nonceConst, 0);
- console.log("Initiating transfer");
- console.log("Amount:", formatUnits(amountParsed, 18));
- console.log("To chain:", recipientChain);
- console.log("To address:", recipientAddress);
- console.log("Fees:", fee);
- console.log("Nonce:", nonceBuffer);
- const bridge = Bridge__factory.connect(
- ETH_TOKEN_BRIDGE_ADDRESS,
- signer
- );
- bridge
- .transferTokens(
- tokenAddress,
- amountParsed,
- recipientChain,
- recipientAddress,
- fee,
- nonceBuffer
- )
- .then((v) => console.log("Success:", v))
- .catch((r) => console.error(r)); //TODO: integrate toast messages
- });
- });
- });
+ const allowance = await token.allowance(
+ signerAddress,
+ ETH_TOKEN_BRIDGE_ADDRESS
+ );
+ console.log("Allowance", allowance.toString()); //TODO: should we check that this is zero and warn if it isn't?
+ const transaction = await token.approve(
+ ETH_TOKEN_BRIDGE_ADDRESS,
+ amountParsed
+ );
+ console.log(transaction);
+ const fee = 0; // for now, this won't do anything, we may add later
+ const nonceConst = Math.random() * 100000;
+ const nonceBuffer = Buffer.alloc(4);
+ nonceBuffer.writeUInt32LE(nonceConst, 0);
+ console.log("Initiating transfer");
+ console.log("Amount:", formatUnits(amountParsed, 18));
+ console.log("To chain:", recipientChain);
+ console.log("To address:", recipientAddress);
+ console.log("Fees:", fee);
+ console.log("Nonce:", nonceBuffer);
+ const bridge = Bridge__factory.connect(ETH_TOKEN_BRIDGE_ADDRESS, signer);
+ const v = await bridge.transferTokens(
+ tokenAddress,
+ amountParsed,
+ recipientChain,
+ recipientAddress,
+ fee,
+ nonceBuffer
+ );
+ const receipt = await v.wait();
+ // TODO: dangerous!(?)
+ const bridgeLog = receipt.logs.filter((l) => {
+ console.log(l.address, ETH_BRIDGE_ADDRESS);
+ return l.address === ETH_BRIDGE_ADDRESS;
+ })[0];
+ const {
+ args: { sender, sequence },
+ } = Implementation__factory.createInterface().parseLog(bridgeLog);
+ console.log(sender, sequence);
+ const emitterAddress = Buffer.from(
+ zeroPad(arrayify(ETH_TOKEN_BRIDGE_ADDRESS), 32)
+ ).toString("hex");
+ const { vaaBytes } = await getSignedVAA(
+ CHAIN_ID_ETH,
+ emitterAddress,
+ sequence
+ );
+ console.log("SIGNED VAA:", vaaBytes);
+ })();
}
// TODO: should we share this with client? ooh, should client use the SDK ;)
@@ -201,8 +218,8 @@ export function transferFromSolana(
console.log("SIGNED", signed);
const txid = await connection.sendRawTransaction(signed.serialize());
console.log("SENT", txid);
- await connection.confirmTransaction(txid);
- console.log("CONFIRMED");
+ const conf = await connection.confirmTransaction(txid);
+ console.log("CONFIRMED", conf);
})();
}
diff --git a/bridge_ui/src/utils/wrappedAsset.ts b/bridge_ui/src/utils/wrappedAsset.ts
new file mode 100644
index 000000000..e6425c066
--- /dev/null
+++ b/bridge_ui/src/utils/wrappedAsset.ts
@@ -0,0 +1,24 @@
+import { PublicKey } from "@solana/web3.js";
+import { ethers } from "ethers";
+import { arrayify, zeroPad } from "ethers/lib/utils";
+import { Bridge__factory } from "../ethers-contracts";
+import { ChainId, CHAIN_ID_SOLANA, ETH_TOKEN_BRIDGE_ADDRESS } from "./consts";
+
+export function wrappedAssetEth(
+ provider: ethers.providers.Web3Provider,
+ originChain: ChainId,
+ originAsset: string
+) {
+ const tokenBridge = Bridge__factory.connect(
+ ETH_TOKEN_BRIDGE_ADDRESS,
+ provider
+ );
+ // TODO: address conversion may be more complex than this
+ const originAssetBytes = zeroPad(
+ originChain === CHAIN_ID_SOLANA
+ ? new PublicKey(originAsset).toBytes()
+ : arrayify(originAsset),
+ 32
+ );
+ return tokenBridge.wrappedAsset(originChain, originAssetBytes);
+}
diff --git a/bridge_ui/tsconfig.json b/bridge_ui/tsconfig.json
index 16fff78a0..c11055884 100644
--- a/bridge_ui/tsconfig.json
+++ b/bridge_ui/tsconfig.json
@@ -17,6 +17,7 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
+ "downlevelIteration": true,
"noEmit": true,
"jsx": "react-jsx"
},
diff --git a/buf.gen.web.yaml b/buf.gen.web.yaml
index 25efe2267..755165432 100644
--- a/buf.gen.web.yaml
+++ b/buf.gen.web.yaml
@@ -19,4 +19,4 @@ plugins:
- env=browser
- forceLong=string
- outputClientImpl=grpc-web
- - explorer/src/proto
+ - bridge_ui/src/proto
diff --git a/tools/package-lock.json b/tools/package-lock.json
index 1704220ae..7720111b8 100644
--- a/tools/package-lock.json
+++ b/tools/package-lock.json
@@ -7,7 +7,7 @@
"": {
"version": "1.0.0",
"devDependencies": {
- "ts-proto": "^1.81.1"
+ "ts-proto": "^1.82.3"
}
},
"node_modules/@protobufjs/aspromise": {
@@ -175,9 +175,9 @@
}
},
"node_modules/ts-proto": {
- "version": "1.82.0",
- "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.82.0.tgz",
- "integrity": "sha512-vo4QN4QhR0D4/+C/pSbRIVSV6U7dooNcuyW3SL9DvhKRQA4lnAbF5QBs77ge3JRi+aSZJm8MlzTNk7+e++fvvQ==",
+ "version": "1.82.3",
+ "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.82.3.tgz",
+ "integrity": "sha512-ODveOXK2imsgTiqkBcJu9mIOklmCTSzs7Xu+mT8Xljwh3Wenhax7bhty+x2eO4J7AfNkikXH0Xs7K3lk3UT8VA==",
"dev": true,
"dependencies": {
"@types/object-hash": "^1.3.0",
@@ -354,9 +354,9 @@
}
},
"ts-proto": {
- "version": "1.82.0",
- "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.82.0.tgz",
- "integrity": "sha512-vo4QN4QhR0D4/+C/pSbRIVSV6U7dooNcuyW3SL9DvhKRQA4lnAbF5QBs77ge3JRi+aSZJm8MlzTNk7+e++fvvQ==",
+ "version": "1.82.3",
+ "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.82.3.tgz",
+ "integrity": "sha512-ODveOXK2imsgTiqkBcJu9mIOklmCTSzs7Xu+mT8Xljwh3Wenhax7bhty+x2eO4J7AfNkikXH0Xs7K3lk3UT8VA==",
"dev": true,
"requires": {
"@types/object-hash": "^1.3.0",
diff --git a/tools/package.json b/tools/package.json
index 83a6c6bd0..56c3c733f 100644
--- a/tools/package.json
+++ b/tools/package.json
@@ -3,7 +3,6 @@
"version": "1.0.0",
"description": "tooling for building web code from protobufs",
"devDependencies": {
- "ts-proto": "^1.81.1"
- },
- "dependencies": {}
+ "ts-proto": "^1.82.3"
+ }
}