diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index de90fd2..f4e55c9 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -23,9 +23,6 @@ jobs: version: 8 run_install: true - - name: Get changes - run: git diff --name-only -r HEAD^1 HEAD - - name: Test run: | npx tsx ./src/verify.ts $(git diff --name-only -r HEAD^1 HEAD) diff --git a/data/TSC/logo.png b/data/TSC/logo.png deleted file mode 100644 index 84a8c60..0000000 Binary files a/data/TSC/logo.png and /dev/null differ diff --git a/data/UNI/data.json b/data/UNI/data.json new file mode 100644 index 0000000..0511156 --- /dev/null +++ b/data/UNI/data.json @@ -0,0 +1,11 @@ +{ + "name": "Uniswap", + "symbol": "UNI", + "decimals": 18, + "logoURI": "https://raw.githubusercontent.com/ethereum-optimism/ethereum-optimism.github.io/cdf02065fa51dd7c934ba857f5a1746513fe8e7f/data/UNI/logo.png", + "opTokenId": "UNI", + "addresses": { + "1": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", + "8453": "0xc3De830EA07524a0761646a6a4e4be0e114a3C83" + } +} \ No newline at end of file diff --git a/data/USDT/data.json b/data/USDT/data.json new file mode 100644 index 0000000..b7d09ea --- /dev/null +++ b/data/USDT/data.json @@ -0,0 +1,11 @@ +{ + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "logoURI": "https://raw.githubusercontent.com/ethereum-optimism/ethereum-optimism.github.io/01d7d6bf2ff3735b412da924d1df746ddd8a77a8/data/USDT/logo.png", + "opTokenId": "USDT", + "addresses": { + "1": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "8453": "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2" + } +} \ No newline at end of file diff --git a/src/abis/L2StandardERC20.ts b/src/abis/L2StandardERC20.ts new file mode 100644 index 0000000..7ae831d --- /dev/null +++ b/src/abis/L2StandardERC20.ts @@ -0,0 +1,225 @@ +export const L2StandardERC20Abi = [ + { + inputs: [ + { internalType: "address", name: "_l2Bridge", type: "address" }, + { internalType: "address", name: "_l1Token", type: "address" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "_account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "Burn", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "_account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "Mint", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_from", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "subtractedValue", type: "uint256" }, + ], + name: "decreaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "addedValue", type: "uint256" }, + ], + name: "increaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "l1Token", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "l2Bridge", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_to", type: "address" }, + { internalType: "uint256", name: "_amount", type: "uint256" }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "sender", type: "address" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/src/verify.ts b/src/verify.ts index 86f6919..822ef19 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -5,6 +5,7 @@ import { isAddressEqual, isAddress } from "viem/utils"; import { OptimismMintableERC20Abi } from "./abis/OptimismMintableERC20"; import { StandardBridgeAbi } from "./abis/StandardBridge"; +import { L2StandardERC20Abi } from "./abis/L2StandardERC20"; import { getViemChain, TokenData } from "./utils"; async function main() { @@ -37,7 +38,7 @@ async function main() { throw new Error(`Invalid address for chainId ${chainId}`); } - const [BRIDGE, REMOTE_TOKEN] = await Promise.all([ + const [BRIDGE, REMOTE_TOKEN, l2Bridge, l1Token] = await Promise.all([ client .readContract({ abi: OptimismMintableERC20Abi, @@ -52,17 +53,34 @@ async function main() { address: address as Address, }) .catch(() => null), + client + .readContract({ + abi: L2StandardERC20Abi, + functionName: "l2Bridge", + address: address as Address, + }) + .catch(() => null), + client + .readContract({ + abi: L2StandardERC20Abi, + functionName: "l1Token", + address: address as Address, + }) + .catch(() => null), ]); console.log("BRIDGE", BRIDGE); console.log("REMOTE_TOKEN", REMOTE_TOKEN); + const localBridge = BRIDGE || l2Bridge; + const remoteToken = REMOTE_TOKEN || l1Token; + // mintable - if (BRIDGE && REMOTE_TOKEN) { + if (localBridge && remoteToken) { mintable = true; console.log(chainId, "is mintable"); const baseChainId = Object.entries(data!.addresses).find( - ([_, address]) => isAddressEqual(address as Address, REMOTE_TOKEN) + ([_, address]) => isAddressEqual(address as Address, remoteToken) ); if (!baseChainId) { throw new Error( @@ -81,7 +99,7 @@ async function main() { .readContract({ abi: StandardBridgeAbi, functionName: "OTHER_BRIDGE", - address: BRIDGE, + address: localBridge, }) .catch(() => null); if (!BASE_BRIDGE) { @@ -101,7 +119,7 @@ async function main() { if (!REMOTE_BRIDGE) { throw new Error("REMOTE_BRIDGE not found"); } - if (!isAddressEqual(REMOTE_BRIDGE, BRIDGE)) { + if (!isAddressEqual(REMOTE_BRIDGE, localBridge)) { throw new Error("Bridge addresses do not match"); } } else {