diff --git a/packages/site/src/utils/snap.ts b/packages/site/src/utils/snap.ts index 72bb7d6..418fdb3 100644 --- a/packages/site/src/utils/snap.ts +++ b/packages/site/src/utils/snap.ts @@ -1,6 +1,6 @@ +import { CeloTransactionRequest } from '@celo-tools/celo-ethers-wrapper'; import { defaultSnapOrigin } from '../config'; import { GetSnapsResponse, Snap } from '../types'; -import { CeloTransactionRequest } from '@celo-tools/celo-ethers-wrapper'; /** * Get the installed snaps in MetaMask. @@ -54,14 +54,14 @@ export const getSnap = async (version?: string): Promise => { export const sendTransaction = async (tx: CeloTransactionRequest) => { await window.ethereum.request({ method: 'wallet_invokeSnap', - params: { - snapId: defaultSnapOrigin, - request: { + params: { + snapId: defaultSnapOrigin, + request: { method: 'celo_sendTransaction', params: { - tx - } - } + tx, + }, + }, }, }); }; diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 8ded9bb..2343c17 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/celo-org/gas-snap.git" }, "source": { - "shasum": "95eYP3Qwd+Z7NbQlu6am1zJ7I7m7klhenmiM/NPWBwA=", + "shasum": "wZUjhbhHIUejFTf4KqE6Is7qSHRp1WbkFpVBoxUyyQw=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/abis/FeeCurrencyWhitelist.ts b/packages/snap/src/abis/FeeCurrencyWhitelist.ts index f7ee424..9638c87 100644 --- a/packages/snap/src/abis/FeeCurrencyWhitelist.ts +++ b/packages/snap/src/abis/FeeCurrencyWhitelist.ts @@ -1,3 +1,3 @@ export const FEE_CURRENCY_WHITELIST_ABI = JSON.parse( - '[{ "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "constant": true, "inputs": [], "name": "initialized", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "isOwner", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "renounceOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "whitelist", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "tokenAddress", "type": "address" } ], "name": "addToken", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "getWhitelist", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" } ], "payable": false, "stateMutability": "view", "type": "function" } ]' + '[{ "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "constant": true, "inputs": [], "name": "initialized", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "isOwner", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "renounceOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "whitelist", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "tokenAddress", "type": "address" } ], "name": "addToken", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "getWhitelist", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" } ], "payable": false, "stateMutability": "view", "type": "function" } ]', ); diff --git a/packages/snap/src/abis/Registry.ts b/packages/snap/src/abis/Registry.ts index a98ad43..e19a822 100644 --- a/packages/snap/src/abis/Registry.ts +++ b/packages/snap/src/abis/Registry.ts @@ -1,3 +1,3 @@ export const REGISTRY_ABI = JSON.parse( - '[ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "string", "name": "identifier", "type": "string" }, { "indexed": true, "internalType": "bytes32", "name": "identifierHash", "type": "bytes32" }, { "indexed": true, "internalType": "address", "name": "addr", "type": "address" } ], "name": "RegistryUpdated", "type": "event" }, { "constant": true, "inputs": [], "name": "initialized", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "isOwner", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32", "name": "", "type": "bytes32" } ], "name": "registry", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "renounceOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "string", "name": "identifier", "type": "string" }, { "internalType": "address", "name": "addr", "type": "address" } ], "name": "setAddressFor", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32", "name": "identifierHash", "type": "bytes32" } ], "name": "getAddressForOrDie", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32", "name": "identifierHash", "type": "bytes32" } ], "name": "getAddressFor", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "string", "name": "identifier", "type": "string" } ], "name": "getAddressForStringOrDie", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "string", "name": "identifier", "type": "string" } ], "name": "getAddressForString", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32[]", "name": "identifierHashes", "type": "bytes32[]" }, { "internalType": "address", "name": "sender", "type": "address" } ], "name": "isOneOf", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ]' + '[ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "string", "name": "identifier", "type": "string" }, { "indexed": true, "internalType": "bytes32", "name": "identifierHash", "type": "bytes32" }, { "indexed": true, "internalType": "address", "name": "addr", "type": "address" } ], "name": "RegistryUpdated", "type": "event" }, { "constant": true, "inputs": [], "name": "initialized", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "isOwner", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32", "name": "", "type": "bytes32" } ], "name": "registry", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "renounceOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "string", "name": "identifier", "type": "string" }, { "internalType": "address", "name": "addr", "type": "address" } ], "name": "setAddressFor", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32", "name": "identifierHash", "type": "bytes32" } ], "name": "getAddressForOrDie", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32", "name": "identifierHash", "type": "bytes32" } ], "name": "getAddressFor", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "string", "name": "identifier", "type": "string" } ], "name": "getAddressForStringOrDie", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "string", "name": "identifier", "type": "string" } ], "name": "getAddressForString", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "bytes32[]", "name": "identifierHashes", "type": "bytes32[]" }, { "internalType": "address", "name": "sender", "type": "address" } ], "name": "isOneOf", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ]', ); diff --git a/packages/snap/src/abis/SortedOracles.ts b/packages/snap/src/abis/SortedOracles.ts index 7a56e3d..8be2f70 100644 --- a/packages/snap/src/abis/SortedOracles.ts +++ b/packages/snap/src/abis/SortedOracles.ts @@ -1,4 +1,3 @@ - export const SORTED_ORACLES_ABI = JSON.parse( - '[ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "MedianUpdated", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracleAddress", "type": "address" } ], "name": "OracleAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracleAddress", "type": "address" } ], "name": "OracleRemoved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracle", "type": "address" } ], "name": "OracleReportRemoved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracle", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "OracleReported", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "uint256", "name": "reportExpiry", "type": "uint256" } ], "name": "ReportExpirySet", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "token", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "reportExpiry", "type": "uint256" } ], "name": "TokenReportExpirySet", "type": "event" }, { "constant": true, "inputs": [], "name": "initialized", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "", "type": "address" }, { "internalType": "address", "name": "", "type": "address" } ], "name": "isOracle", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "isOwner", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "", "type": "address" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "oracles", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "renounceOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "reportExpirySeconds", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "", "type": "address" } ], "name": "tokenReportExpirySeconds", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "getVersionNumber", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "pure", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "uint256", "name": "_reportExpirySeconds", "type": "uint256" } ], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "uint256", "name": "_reportExpirySeconds", "type": "uint256" } ], "name": "setReportExpiry", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "_token", "type": "address" }, { "internalType": "uint256", "name": "_reportExpirySeconds", "type": "uint256" } ], "name": "setTokenReportExpiry", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "address", "name": "oracleAddress", "type": "address" } ], "name": "addOracle", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "address", "name": "oracleAddress", "type": "address" }, { "internalType": "uint256", "name": "index", "type": "uint256" } ], "name": "removeOracle", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "n", "type": "uint256" } ], "name": "removeExpiredReports", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "isOldestReportExpired", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" }, { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "address", "name": "lesserKey", "type": "address" }, { "internalType": "address", "name": "greaterKey", "type": "address" } ], "name": "report", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "numRates", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "medianRate", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getRates", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" }, { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, { "internalType": "enum SortedLinkedListWithMedian.MedianRelation[]", "name": "", "type": "uint8[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "numTimestamps", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "medianTimestamp", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getTimestamps", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" }, { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, { "internalType": "enum SortedLinkedListWithMedian.MedianRelation[]", "name": "", "type": "uint8[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getOracles", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getTokenReportExpirySeconds", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" } ]' + '[ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "MedianUpdated", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracleAddress", "type": "address" } ], "name": "OracleAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracleAddress", "type": "address" } ], "name": "OracleRemoved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracle", "type": "address" } ], "name": "OracleReportRemoved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": true, "internalType": "address", "name": "oracle", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "OracleReported", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "uint256", "name": "reportExpiry", "type": "uint256" } ], "name": "ReportExpirySet", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "token", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "reportExpiry", "type": "uint256" } ], "name": "TokenReportExpirySet", "type": "event" }, { "constant": true, "inputs": [], "name": "initialized", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "", "type": "address" }, { "internalType": "address", "name": "", "type": "address" } ], "name": "isOracle", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "isOwner", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "", "type": "address" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "oracles", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "renounceOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "reportExpirySeconds", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "", "type": "address" } ], "name": "tokenReportExpirySeconds", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "getVersionNumber", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "pure", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "uint256", "name": "_reportExpirySeconds", "type": "uint256" } ], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "uint256", "name": "_reportExpirySeconds", "type": "uint256" } ], "name": "setReportExpiry", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "_token", "type": "address" }, { "internalType": "uint256", "name": "_reportExpirySeconds", "type": "uint256" } ], "name": "setTokenReportExpiry", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "address", "name": "oracleAddress", "type": "address" } ], "name": "addOracle", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "address", "name": "oracleAddress", "type": "address" }, { "internalType": "uint256", "name": "index", "type": "uint256" } ], "name": "removeOracle", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "n", "type": "uint256" } ], "name": "removeExpiredReports", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "isOldestReportExpired", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" }, { "internalType": "address", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "address", "name": "lesserKey", "type": "address" }, { "internalType": "address", "name": "greaterKey", "type": "address" } ], "name": "report", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "numRates", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "medianRate", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getRates", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" }, { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, { "internalType": "enum SortedLinkedListWithMedian.MedianRelation[]", "name": "", "type": "uint8[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "numTimestamps", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "medianTimestamp", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getTimestamps", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" }, { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, { "internalType": "enum SortedLinkedListWithMedian.MedianRelation[]", "name": "", "type": "uint8[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getOracles", "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "internalType": "address", "name": "token", "type": "address" } ], "name": "getTokenReportExpirySeconds", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" } ]', ); diff --git a/packages/snap/src/abis/StableToken.ts b/packages/snap/src/abis/StableToken.ts index 2aad4e8..ee85c90 100644 --- a/packages/snap/src/abis/StableToken.ts +++ b/packages/snap/src/abis/StableToken.ts @@ -1,3 +1,3 @@ export const STABLE_TOKEN_ABI = JSON.parse( - '[{"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":false,"internalType":"uint256","name":"factor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastUpdated","type":"uint256"}],"name":"InflationFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastUpdated","type":"uint256"}],"name":"InflationParametersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registryAddress","type":"address"}],"name":"RegistrySet","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"comment","type":"string"}],"name":"TransferComment","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"blsKey","type":"bytes"},{"internalType":"bytes","name":"blsPop","type":"bytes"}],"name":"checkProofOfPossession","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"aNumerator","type":"uint256"},{"internalType":"uint256","name":"aDenominator","type":"uint256"},{"internalType":"uint256","name":"bNumerator","type":"uint256"},{"internalType":"uint256","name":"bDenominator","type":"uint256"},{"internalType":"uint256","name":"exponent","type":"uint256"},{"internalType":"uint256","name":"_decimals","type":"uint256"}],"name":"fractionMulExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"getBlockNumberFromHeader","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEpochNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getEpochNumberOfBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEpochSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getParentSealBitmap","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"getVerifiedSealBitmapFromHeader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"hashHeader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"minQuorumSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minQuorumSizeInCurrentSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"numberValidatorsInCurrentSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"numberValidatorsInSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"registry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"registryAddress","type":"address"}],"name":"setRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"validatorSignerAddressFromCurrentSet","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"validatorSignerAddressFromSet","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getVersionNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"registryAddress","type":"address"},{"internalType":"uint256","name":"inflationRate","type":"uint256"},{"internalType":"uint256","name":"inflationFactorUpdatePeriod","type":"uint256"},{"internalType":"address[]","name":"initialBalanceAddresses","type":"address[]"},{"internalType":"uint256[]","name":"initialBalanceValues","type":"uint256[]"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"updatePeriod","type":"uint256"}],"name":"setInflationParameters","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"string","name":"comment","type":"string"}],"name":"transferWithComment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"accountOwner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"accountOwner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInflationParameters","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"valueToUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"units","type":"uint256"}],"name":"unitsToValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"debitGasFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"gatewayFeeRecipient","type":"address"},{"internalType":"address","name":"communityFund","type":"address"},{"internalType":"uint256","name":"refund","type":"uint256"},{"internalType":"uint256","name":"tipTxFee","type":"uint256"},{"internalType":"uint256","name":"gatewayFee","type":"uint256"},{"internalType":"uint256","name":"baseTxFee","type":"uint256"}],"name":"creditGasFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]' + '[{"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":false,"internalType":"uint256","name":"factor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastUpdated","type":"uint256"}],"name":"InflationFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastUpdated","type":"uint256"}],"name":"InflationParametersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registryAddress","type":"address"}],"name":"RegistrySet","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"comment","type":"string"}],"name":"TransferComment","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"blsKey","type":"bytes"},{"internalType":"bytes","name":"blsPop","type":"bytes"}],"name":"checkProofOfPossession","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"aNumerator","type":"uint256"},{"internalType":"uint256","name":"aDenominator","type":"uint256"},{"internalType":"uint256","name":"bNumerator","type":"uint256"},{"internalType":"uint256","name":"bDenominator","type":"uint256"},{"internalType":"uint256","name":"exponent","type":"uint256"},{"internalType":"uint256","name":"_decimals","type":"uint256"}],"name":"fractionMulExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"getBlockNumberFromHeader","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEpochNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getEpochNumberOfBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEpochSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getParentSealBitmap","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"getVerifiedSealBitmapFromHeader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"hashHeader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"minQuorumSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minQuorumSizeInCurrentSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"numberValidatorsInCurrentSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"numberValidatorsInSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"registry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"registryAddress","type":"address"}],"name":"setRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"validatorSignerAddressFromCurrentSet","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"validatorSignerAddressFromSet","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getVersionNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"registryAddress","type":"address"},{"internalType":"uint256","name":"inflationRate","type":"uint256"},{"internalType":"uint256","name":"inflationFactorUpdatePeriod","type":"uint256"},{"internalType":"address[]","name":"initialBalanceAddresses","type":"address[]"},{"internalType":"uint256[]","name":"initialBalanceValues","type":"uint256[]"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"updatePeriod","type":"uint256"}],"name":"setInflationParameters","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"string","name":"comment","type":"string"}],"name":"transferWithComment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"accountOwner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"accountOwner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInflationParameters","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"valueToUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"units","type":"uint256"}],"name":"unitsToValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"debitGasFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"gatewayFeeRecipient","type":"address"},{"internalType":"address","name":"communityFund","type":"address"},{"internalType":"uint256","name":"refund","type":"uint256"},{"internalType":"uint256","name":"tipTxFee","type":"uint256"},{"internalType":"uint256","name":"gatewayFee","type":"uint256"},{"internalType":"uint256","name":"baseTxFee","type":"uint256"}],"name":"creditGasFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]', ); diff --git a/packages/snap/src/constants.ts b/packages/snap/src/constants.ts index a915329..6536158 100644 --- a/packages/snap/src/constants.ts +++ b/packages/snap/src/constants.ts @@ -3,6 +3,6 @@ // export const REGISTRY_CONTRACT = require("./abis/Registry.json"); // export const STABLE_TOKEN_CONTRACT = require("./abis/StableToken.json"); -export const REGISTRY_ADDRESS = "0x000000000000000000000000000000000000ce10"; -export const CELO_MAINNET = "mainnet"; -export const CELO_ALFAJORES = "alfajores"; +export const REGISTRY_ADDRESS = '0x000000000000000000000000000000000000ce10'; +export const CELO_MAINNET = 'mainnet'; +export const CELO_ALFAJORES = 'alfajores'; diff --git a/packages/snap/src/currency.ts b/packages/snap/src/currency.ts new file mode 100644 index 0000000..74a20a5 --- /dev/null +++ b/packages/snap/src/currency.ts @@ -0,0 +1,197 @@ +// TODO Retrieve this onchain, this would need Update to the FeeCurrencyWhitelist.sol + +import { + CeloTransactionRequest, + CeloWallet, +} from '@celo-tools/celo-ethers-wrapper'; +import { BigNumber, Contract, ethers } from 'ethers'; +import { CELO_ALFAJORES, CELO_MAINNET, REGISTRY_ADDRESS } from './constants'; +import { REGISTRY_ABI } from './abis/Registry'; +import { SORTED_ORACLES_ABI } from './abis/SortedOracles'; +import { FEE_CURRENCY_WHITELIST_ABI } from './abis/FeeCurrencyWhitelist'; +import { SortedOraclesRates, TokenInfo } from './utils/types'; +import { STABLE_TOKEN_ABI } from './abis/stableToken'; + +// contract to also store currency name. +/** + * + * @param feeCurrencyAddress + * @param network + */ +export function getFeeCurrencyNameFromAddress( + feeCurrencyAddress: string | undefined, + network: string, +): string { + switch (network) { + case CELO_ALFAJORES: + switch (feeCurrencyAddress) { + case undefined: + return 'celo'; + case '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1': + return 'cusd'; + case '0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F': + return 'ceur'; + case '0xE4D517785D091D3c54818832dB6094bcc2744545': + return 'creal'; + default: + throw new Error( + `Fee currency address ${feeCurrencyAddress} not recognized.`, + ); + } + + case CELO_MAINNET: + switch (feeCurrencyAddress) { + case undefined: + return 'celo'; + case '0x765DE816845861e75A25fCA122bb6898B8B1282a': + return 'cusd'; + case '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73': + return 'ceur'; + case '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787': + return 'creal'; + default: + throw new Error( + `Fee currency address ${feeCurrencyAddress} not recognized.`, + ); + } + + default: + throw new Error(`Network ${network} not recognized.`); + } +} + +/** + * + * @param feeCurrencyName + * @param network + */ +export function getFeeCurrencyAddressFromName( + feeCurrencyName: string, + network: string, +): string | undefined { + switch (network) { + case CELO_ALFAJORES: + switch (feeCurrencyName) { + case 'celo': + return undefined; + case 'cusd': + return '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1'; + case 'ceur': + return '0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F'; + case 'creal': + return '0xE4D517785D091D3c54818832dB6094bcc2744545'; + default: + throw new Error( + `Fee currency string ${feeCurrencyName} not recognized. Must be either 'celo', 'cusd', 'ceur' or 'creal'.`, + ); + } + + case CELO_MAINNET: + switch (feeCurrencyName) { + case 'celo': + return undefined; + case 'cusd': + return '0x765DE816845861e75A25fCA122bb6898B8B1282a'; + case 'ceur': + return '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73'; + case 'creal': + return '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787'; + default: + throw new Error( + `Fee currency string ${feeCurrencyName} not recognized. Must be either 'celo', 'cusd', 'ceur' or 'creal'.`, + ); + } + } +} + +/** + * Finds the optimal gas currency to send a transaction with based on user balances. + * This may differ from the feeCurrency specified in the transaction body. + * + * The returned feeCurrency will be Celo if the user has enough balance + * to pay for the transaction in Celo, as native transactions are cheaper. + * Otherwise, the returned feeCurrency will be whichever one the user would + * have the greatest balance in after sending the transaction. + * + * @param tx - The transaction to select the optimal gas currency for + * @param wallet + * @returns - The address of the optimal feeCurrency, or undefined if the optimal + * feeCurrency is Celo. + */ +export async function getOptimalFeeCurrency( + tx: CeloTransactionRequest, + wallet: CeloWallet, +): Promise { + const registry = new Contract(REGISTRY_ADDRESS, REGISTRY_ABI, wallet); + const sortedOraclesAddress = await registry.getAddressForString( + 'SortedOracles', + ); + const feeCurrencyWhitelistAddress = await registry.getAddressForString( + 'FeeCurrencyWhitelist', + ); + const sortedOraclesContract = new Contract( + sortedOraclesAddress, + SORTED_ORACLES_ABI, + wallet, + ); + const feeCurrencyWhitelistContract = new Contract( + feeCurrencyWhitelistAddress, + FEE_CURRENCY_WHITELIST_ABI, + wallet, + ); + const gasLimit = (await wallet.estimateGas(tx)).mul(5); + const celoBalance = await wallet.getBalance(); + const tokenAddresses = await feeCurrencyWhitelistContract.getWhitelist(); + + if (gasLimit.add(tx.value ?? 0) >= celoBalance) { + console.log('using stable token for gas'); + const tokens: Contract[] = tokenAddresses.map( + (tokenAddress: string) => + new Contract(tokenAddress, STABLE_TOKEN_ABI, wallet), + ); + + const [ratesResults, balanceResults] = await Promise.all([ + Promise.allSettled( + tokens.map( + (t) => sortedOraclesContract.medianRate(t.address) as BigNumber[], + ), + ), + Promise.allSettled( + tokens.map((t) => t.balanceOf(wallet.address) as BigNumber), + ), + ]); + + const tokenInfos: TokenInfo[] = []; + + for (let i = 0; i < tokens.length; i++) { + const [address, ratesRes, balanceRes] = [ + tokens[i].address, + ratesResults[i], + balanceResults[i], + ]; + const rates = + ratesRes.status === 'fulfilled' + ? ({ + numerator: ratesRes.value[0], + denominator: ratesRes.value[1], + } as SortedOraclesRates) + : undefined; + const balance = + balanceRes.status === 'fulfilled' ? balanceRes.value : undefined; + const value = + rates && balance + ? balance.mul(rates.numerator.div(rates.denominator)) + : ethers.constants.Zero; + tokenInfos.push({ address, value, rates, balance }); + } + + // TODO: consider edge case where the transaction itself sends a stable token + // sort in descending order + const sortedTokenInfos = tokenInfos.sort((a, b) => + b.value.sub(a.value).toNumber(), + ); + + return sortedTokenInfos[0].address; + } + return undefined; +} diff --git a/packages/snap/src/getKeyPair.ts b/packages/snap/src/getKeyPair.ts new file mode 100644 index 0000000..bd32be6 --- /dev/null +++ b/packages/snap/src/getKeyPair.ts @@ -0,0 +1,77 @@ +import { SnapsGlobalObject } from '@metamask/snaps-types'; +import { panel, text } from '@metamask/snaps-ui'; +import { + getBIP44AddressKeyDeriver, + BIP44Node, + JsonBIP44CoinTypeNode, +} from '@metamask/key-tree'; +import { KeyPair } from './utils/types'; + +/** + * + * @param snap + * @param address + * @param addressIndex + */ +export async function getKeyPair( + snap: SnapsGlobalObject, + address?: string, + addressIndex = 0, +): Promise { + const derivationPath = "m/44'/60'/0'/0"; // Todo - read from state config + let derivedKey; + let _addressIndex = 0; + const MAX_SEARCH_DEPTH = 50; + + const [, , coinType, account, change] = derivationPath.split('/'); + const bip44Code = coinType.replace("'", ''); + + const bip44Node = (await snap.request({ + method: 'snap_getBip44Entropy', + params: { + coinType: Number(bip44Code), + }, + })) as JsonBIP44CoinTypeNode; + + const addressKeyDeriver = await getBIP44AddressKeyDeriver(bip44Node, { + account: parseInt(account), + change: parseInt(change), + }); + + if (address) { + let search; + do { + search = await addressKeyDeriver(Number(_addressIndex)); + if (search.address.toLowerCase() == address.toLowerCase()) { + derivedKey = search; + } + _addressIndex += 1; + } while ( + address.toLowerCase() != search.address.toLowerCase() && + _addressIndex <= MAX_SEARCH_DEPTH + ); + } else { + derivedKey = await addressKeyDeriver(Number(addressIndex)); + } + + if (!derivedKey) { + await snap.request({ + method: 'snap_dialog', + params: { + type: 'alert', + content: panel([ + text( + `The Transaction specifies from ${address} however that address could not be signed by the private key derived from the MetaMask Mnemonic.`, + ), + ]), + }, + }); + throw new Error('Unable to locate private key for account'); + } + + return { + address: derivedKey.address, + privateKey: derivedKey.privateKey, + publicKey: derivedKey.publicKey, + }; +} diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 283365b..ee31508 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -1,17 +1,21 @@ -import { OnRpcRequestHandler, SnapsGlobalObject } from '@metamask/snaps-types' -import { panel, text, copyable } from '@metamask/snaps-ui' -import { CeloProvider, CeloTransactionRequest, CeloWallet } from '@celo-tools/celo-ethers-wrapper' -import { Contract, BigNumber, ethers, constants } from 'ethers' -import { getBIP44AddressKeyDeriver, BIP44Node , JsonBIP44CoinTypeNode} from '@metamask/key-tree' -import { Network, getNetwork } from './utils/network' -import { RequestParamsSchema, SortedOraclesRates, TokenInfo, InsufficientFundsError, KeyPair } from './utils/types' -// import { STABLE_TOKEN_CONTRACT } from './constants' -import { STABLE_TOKEN_ABI } from './abis/stableToken' -import { REGISTRY_ABI } from './abis/Registry' -import { SORTED_ORACLES_ABI } from './abis/SortedOracles' -import { FEE_CURRENCY_WHITELIST_ABI } from './abis/FeeCurrencyWhitelist' -import { CELO_ALFAJORES, CELO_MAINNET, REGISTRY_ADDRESS } from './constants' -import { handleNumber, isInsufficientFundsError } from './utils/utils' +import { OnRpcRequestHandler, SnapsGlobalObject } from '@metamask/snaps-types'; +import { + CeloProvider, + CeloTransactionRequest, + CeloWallet, +} from '@celo-tools/celo-ethers-wrapper'; +import { constants } from 'ethers'; +import { getNetworkConfig } from './utils/network'; +import { RequestParamsSchema } from './utils/types'; +import { handleNumber, isInsufficientFundsError } from './utils/utils'; +import { sendTransaction } from './sendTransaction'; +import { getKeyPair } from './getKeyPair'; +import { + getFeeCurrencyAddressFromName, + getFeeCurrencyNameFromAddress, + getOptimalFeeCurrency, +} from './currency'; +import { invokeSnapDialog } from './utils/snapDialog'; /** * Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`. @@ -21,58 +25,50 @@ import { handleNumber, isInsufficientFundsError } from './utils/utils' * invoked the snap. * @param args.request - A validated JSON-RPC request object. * @returns The result of `snap_dialog`. - * @throws If the request method is not valid for this snap, or if the request params are invalid. + * @throws If the request method is not valid for this snap, or if the request params are invalid. */ -export const onRpcRequest: OnRpcRequestHandler = async ({ origin, request }) => { +export const onRpcRequest: OnRpcRequestHandler = async ({ + origin, + request, +}) => { if (!RequestParamsSchema.is(request.params)) { - await snap.request({ - method: 'snap_dialog', - params: { - type: 'alert', - content: panel([ - text(`Invalid Request!`), - text(`${JSON.stringify(request.params)}`), - ]), - }, + await invokeSnapDialog({ + type: 'alert', + contentArray: ['Invalid Request!', `${JSON.stringify(request.params)}`], }); - return; } - const tx: CeloTransactionRequest = request.params.tx; - tx.value = handleNumber(tx.value) // todo find way to do this within io-ts transformation + const { tx } = request.params; + tx.value = handleNumber(tx.value); // todo find way to do this within io-ts transformation const network = await getNetworkConfig(); const provider = new CeloProvider(network.url); const keyPair = await getKeyPair(snap, tx.from); const wallet = new CeloWallet(keyPair.privateKey).connect(provider); - tx.from = tx.from ? tx.from : wallet.address; if (tx.value == constants.Zero) { delete tx.value; } - let panelContent = [ - text('Please approve the following transaction'), - tx.to && text(`to: ${tx.to}`), - tx.from && text(`from: ${tx.from}`), - tx.nonce && text(`nonce: ${tx.nonce}`), - tx.gasLimit && text(`gasLimit: ${tx.gasLimit}`), - tx.gasPrice && text(`gasPrice: ${tx.gasPrice}`), - tx.data && text(`data: ${tx.data}`), - tx.value && text(`value: ${BigInt(tx.value?.toString())} wei`), - tx.chainId && text(`chainId: ${tx.chainId}`), - tx.feeCurrency && text(`feeCurrency: ${tx.feeCurrency}`), - tx.gatewayFeeRecipient && text(`gatewayFeeRecipient: ${tx.gatewayFeeRecipient}`), - tx.gatewayFee && text(`gatewayFee: ${tx.gatewayFee}`), - ].filter(Boolean) - switch (request.method) { case 'celo_sendTransaction': - const result = await snap.request({ - method: 'snap_dialog', - params: { - type: 'confirmation', - content: panel(panelContent), - }, + const result = await invokeSnapDialog({ + type: 'confirmation', + contentArray: [ + 'Please approve the following transaction', + tx.to ? `to: ${tx.to}` : '', + tx.from ? `from: ${tx.from}` : '', + tx.nonce ? `nonce: ${tx.nonce}` : '', + tx.gasLimit ? `gasLimit: ${tx.gasLimit}` : '', + tx.gasPrice ? `gasPrice: ${tx.gasPrice}` : '', + tx.data ? `data: ${tx.data}` : '', + tx.value ? `value: ${BigInt(tx.value?.toString())} wei` : '', + tx.chainId ? `chainId: ${tx.chainId}` : '', + tx.feeCurrency ? `feeCurrency: ${tx.feeCurrency}` : '', + tx.gatewayFeeRecipient + ? `gatewayFeeRecipient: ${tx.gatewayFeeRecipient}` + : '', + tx.gatewayFee ? `gatewayFee: ${tx.gatewayFee}` : '', + ].filter(Boolean), // This will remove any empty strings }); if (result === true) { @@ -82,21 +78,14 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ origin, request }) => network.name, ); - const overrideFeeCurrency = await snap.request({ - method: 'snap_dialog', - params: { - type: 'prompt', - content: panel([ - text( - `The suggested gas currency for your tx is ${suggestedFeeCurrency}`, - ), - text( - `If you would like to use a different gas currency, please enter it below`, - ), - text(`Otherwise, press submit`), - ]), - placeholder: `'cusd', 'ceur', 'creal', 'celo'`, - }, + const overrideFeeCurrency = await invokeSnapDialog({ + type: 'prompt', + contentArray: [ + `The suggested gas currency for your tx is ${suggestedFeeCurrency}`, + `If you would like to use a different gas currency, please enter it below`, + `Otherwise, press submit`, + ], + placeholder: `'cusd', 'ceur', 'creal', 'celo'`, }); if ( // TODO find a cleaner way to do this, probably use an enum @@ -109,253 +98,36 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ origin, request }) => overrideFeeCurrency, network.name, ); - } else if ( overrideFeeCurrency === null) { + } else if (overrideFeeCurrency === null) { return; } try { const txReceipt = await sendTransaction(tx, wallet); - await snap.request({ - method: 'snap_dialog', - params: { - type: 'alert', - content: panel([ - text(`Your transaction succeeded!`), - copyable(`${network.explorer}/tx/${txReceipt.transactionHash}`), - ]), - }, + await invokeSnapDialog({ + type: 'alert', + contentArray: [ + 'Your transaction succeeded!', + `${network.explorer}/tx/${txReceipt.transactionHash}`, + ], }); } catch (error) { let message = JSON.stringify(error); if (isInsufficientFundsError(error)) { - message = - `Oops! Looks like you don't have sufficient funds in the chosen gas currency to complete the operation. Please try again using another currency.`; + message = `Oops! Looks like you don't have sufficient funds in the chosen gas currency to complete the operation. Please try again using another currency.`; } - await snap.request({ - method: 'snap_dialog', - params: { - type: 'alert', - content: panel([ - text(`Your transaction failed!`), - text(`error: ${message}`), - ]), - }, + await invokeSnapDialog({ + type: 'alert', + contentArray: ['Your transaction failed!', `error: ${message}`], }); } - } else { + } else { // user didn't proceed with transaction - return; } break; default: throw new Error('Method not found.'); } -} - -async function getNetworkConfig(): Promise { - const chainId = await ethereum.request({ method: 'eth_chainId' }) as string - return getNetwork(chainId) -} - -async function sendTransaction(tx: CeloTransactionRequest, wallet: CeloWallet) { - const txResponse = await wallet.sendTransaction({ - ...tx, - gasLimit: (await wallet.estimateGas(tx)).mul(5), - gasPrice: await wallet.getGasPrice(tx.feeCurrency) - }) - - return txResponse.wait() -} - -async function getKeyPair(snap: SnapsGlobalObject, address?: string, addressIndex: number = 0): Promise { - const derivationPath = "m/44'/60'/0'/0"; //Todo - read from state config - let derivedKey; - let _addressIndex = 0; - const MAX_SEARCH_DEPTH = 50; - - const [, , coinType, account, change] = derivationPath.split('/'); - const bip44Code = coinType.replace("'", ''); - - const bip44Node = (await snap.request({ - method: 'snap_getBip44Entropy', - params: { - coinType: Number(bip44Code), - }, - })) as JsonBIP44CoinTypeNode; - - const addressKeyDeriver = await getBIP44AddressKeyDeriver(bip44Node, { - account: parseInt(account), - change: parseInt(change), - }); - - if (address) { - let search; - do { - search = await addressKeyDeriver(Number(_addressIndex)); - if (search.address.toLowerCase() == address.toLowerCase()) { - derivedKey = search - } - _addressIndex = _addressIndex + 1; - } while ( - address.toLowerCase() != search.address.toLowerCase() && - _addressIndex <= MAX_SEARCH_DEPTH - ); - } else { - derivedKey = await addressKeyDeriver(Number(addressIndex)); - } - - if (!derivedKey) { - await snap.request({ - method: 'snap_dialog', - params: { - type: 'alert', - content: panel([ - text(`The Transaction specifies from ${address} however that address could not be signed by the private key derived from the MetaMask Mnemonic.`), - ]) - } - }) - throw new Error('Unable to locate private key for account') - } - - return { - address: derivedKey.address, - privateKey: derivedKey.privateKey, - publicKey: derivedKey.publicKey, - }; -} -/** - * Finds the optimal gas currency to send a transaction with based on user balances. - * This may differ from the feeCurrency specified in the transaction body. - * - * The returned feeCurrency will be Celo if the user has enough balance - * to pay for the transaction in Celo, as native transactions are cheaper. - * Otherwise, the returned feeCurrency will be whichever one the user would - * have the greatest balance in after sending the transaction. - * - * @param tx - The transaction to select the optimal gas currency for - * @returns - The address of the optimal feeCurrency, or undefined if the optimal - * feeCurrency is Celo. - */ -async function getOptimalFeeCurrency(tx: CeloTransactionRequest, wallet: CeloWallet): Promise { - const registry = new Contract(REGISTRY_ADDRESS, REGISTRY_ABI, wallet); - const sortedOraclesAddress = await registry.getAddressForString("SortedOracles"); - const feeCurrencyWhitelistAddress = await registry.getAddressForString("FeeCurrencyWhitelist"); - const sortedOraclesContract = new Contract(sortedOraclesAddress, SORTED_ORACLES_ABI, wallet); - const feeCurrencyWhitelistContract = new Contract(feeCurrencyWhitelistAddress, FEE_CURRENCY_WHITELIST_ABI, wallet); - const gasLimit = (await wallet.estimateGas(tx)).mul(5) - const celoBalance = await wallet.getBalance(); - const tokenAddresses = await feeCurrencyWhitelistContract.getWhitelist(); - const gasLimitPlusValue = gasLimit.add(tx.value ?? 0); - if (gasLimitPlusValue.gt(celoBalance)) { - console.log("using stable token for gas") - const tokens: Contract[] = tokenAddresses.map((tokenAddress: string) => new Contract(tokenAddress, STABLE_TOKEN_ABI, wallet)) - - const [ - ratesResults, - balanceResults - ] = await Promise.all([ - Promise.allSettled(tokens.map((t) => sortedOraclesContract.medianRate(t.address) as BigNumber[])), - Promise.allSettled(tokens.map((t) => t.balanceOf(wallet.address) as BigNumber)) - ]) - - const tokenInfos: TokenInfo[] = [] - - for (let i = 0; i < tokens.length; i++) { - const [address, ratesRes, balanceRes] = [tokens[i].address, ratesResults[i], balanceResults[i]] - const rates = ratesRes.status === "fulfilled" ? { - numerator: ratesRes.value[0], - denominator: ratesRes.value[1] - } as SortedOraclesRates : undefined - const balance = balanceRes.status === "fulfilled" ? balanceRes.value : undefined - const value = (rates && balance) ? balance.mul(rates.numerator.div(rates.denominator)) : ethers.constants.Zero - tokenInfos.push({ address, value, rates, balance }) - } - - // TODO: consider edge case where the transaction itself sends a stable token - // sort in descending order - const sortedTokenInfos = tokenInfos.sort((a, b) => b.value.sub(a.value).toNumber()) - - return sortedTokenInfos[0].address; - } - return undefined; -} - -// TODO Retrieve this onchain, this would need Update to the FeeCurrencyWhitelist.sol -// contract to also store currency name. -function getFeeCurrencyNameFromAddress(feeCurrencyAddress: string | undefined, network: string): string { - switch (network) { - case CELO_ALFAJORES: - switch (feeCurrencyAddress) { - case undefined: - return 'celo' - case '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1': - return 'cusd' - case '0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F': - return 'ceur' - case '0xE4D517785D091D3c54818832dB6094bcc2744545': - return 'creal' - default: - throw new Error( - `Fee currency address ${feeCurrencyAddress} not recognized.` - ) - } - - case CELO_MAINNET: - switch (feeCurrencyAddress) { - case undefined: - return 'celo' - case '0x765DE816845861e75A25fCA122bb6898B8B1282a': - return 'cusd' - case '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73': - return 'ceur' - case '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787': - return 'creal' - default: - throw new Error( - `Fee currency address ${feeCurrencyAddress} not recognized.` - ) - } - - default: - throw new Error( - `Network ${network} not recognized.` - ) - } -} - -function getFeeCurrencyAddressFromName(feeCurrencyName: string, network: string): string | undefined { - switch (network) { - case CELO_ALFAJORES: - switch (feeCurrencyName) { - case 'celo': - return undefined - case 'cusd': - return '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1' - case 'ceur': - return '0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F' - case 'creal': - return '0xE4D517785D091D3c54818832dB6094bcc2744545' - default: - throw new Error( - `Fee currency string ${feeCurrencyName} not recognized. Must be either 'celo', 'cusd', 'ceur' or 'creal'.` - ) - } - case CELO_MAINNET: - switch (feeCurrencyName) { - case 'celo': - return undefined - case 'cusd': - return '0x765DE816845861e75A25fCA122bb6898B8B1282a' - case 'ceur': - return '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73' - case 'creal': - return '0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787' - default: - throw new Error( - `Fee currency string ${feeCurrencyName} not recognized. Must be either 'celo', 'cusd', 'ceur' or 'creal'.` - ) - } - } -} +}; diff --git a/packages/snap/src/sendTransaction.ts b/packages/snap/src/sendTransaction.ts new file mode 100644 index 0000000..4b062ba --- /dev/null +++ b/packages/snap/src/sendTransaction.ts @@ -0,0 +1,22 @@ +import { + CeloTransactionRequest, + CeloWallet, +} from '@celo-tools/celo-ethers-wrapper'; + +/** + * + * @param tx + * @param wallet + */ +export async function sendTransaction( + tx: CeloTransactionRequest, + wallet: CeloWallet, +) { + const txResponse = await wallet.sendTransaction({ + ...tx, + gasLimit: (await wallet.estimateGas(tx)).mul(5), + gasPrice: await wallet.getGasPrice(tx.feeCurrency), + }); + + return txResponse.wait(); +} diff --git a/packages/snap/src/utils/network.ts b/packages/snap/src/utils/network.ts index 23c23f6..85ae4cb 100644 --- a/packages/snap/src/utils/network.ts +++ b/packages/snap/src/utils/network.ts @@ -1,33 +1,42 @@ -import { CELO_ALFAJORES, CELO_MAINNET } from "../constants"; +import { CELO_ALFAJORES, CELO_MAINNET } from '../constants'; +const networks = [ + { + name: CELO_ALFAJORES, + chainIdHex: '0xaef3', + chainIdDecimal: 44787, + url: 'https://alfajores-forno.celo-testnet.org', + explorer: 'https://explorer.celo.org/alfajores', + }, + { + name: CELO_MAINNET, + chainIdHex: '0xa4ec', + chainIdDecimal: 42220, + url: 'https://forno.celo.org', + explorer: 'https://explorer.celo.org/mainnet', + }, +]; -const networks = [{ - "name": CELO_ALFAJORES, - "chainIdHex": "0xaef3", - "chainIdDecimal": 44787, - "url": "https://alfajores-forno.celo-testnet.org", - "explorer": "https://explorer.celo.org/alfajores" -}, { - "name": CELO_MAINNET, - "chainIdHex": "0xa4ec", - "chainIdDecimal": 42220, - "url": "https://forno.celo.org", - "explorer": "https://explorer.celo.org/mainnet" -} -] - -export interface Network { - name: string; - chainIdHex: string, - chainIdDecimal: number, - url: string, - explorer: string -} +export type Network = { + name: string; + chainIdHex: string; + chainIdDecimal: number; + url: string; + explorer: string; +}; export const getNetwork = (chainId: string): Network => { - const network = networks.filter((n: Network) => n.chainIdHex == chainId) - if (network.length == 0) { - throw new Error("Unsupported Network") - } - return network[0]; + const network = networks.filter((n: Network) => n.chainIdHex == chainId); + if (network.length == 0) { + throw new Error('Unsupported Network'); + } + return network[0]; }; + +/** + * + */ +export async function getNetworkConfig(): Promise { + const chainId = (await ethereum.request({ method: 'eth_chainId' })) as string; + return getNetwork(chainId); +} diff --git a/packages/snap/src/utils/snapDialog.ts b/packages/snap/src/utils/snapDialog.ts new file mode 100644 index 0000000..43fc1b5 --- /dev/null +++ b/packages/snap/src/utils/snapDialog.ts @@ -0,0 +1,41 @@ +import { panel, text } from '@metamask/snaps-ui'; + +type DialogType = 'alert' | 'confirmation' | 'prompt'; + +type SnapDialogOptions = { + type: DialogType; + contentArray: string[]; + placeholder?: string; +}; + +/** + * + * @param options0 + * @param options0.type + * @param options0.contentArray + * @param options0.placeholder + */ +export async function invokeSnapDialog({ + type, + contentArray, + placeholder, +}: SnapDialogOptions) { + // Construct the content for the panel using the contentArray + const panelContent = contentArray.map((content) => text(content)); + + // Construct the basic dialog request object + const dialogRequest = { + method: 'snap_dialog', + params: { + type, + content: panel(panelContent), + }, + }; + + // If it's a prompt type and a placeholder is provided, add it to the request + if (type === 'prompt' && placeholder) { + dialogRequest.params.placeholder = placeholder; + } + + return await snap.request(dialogRequest); +} diff --git a/packages/snap/src/utils/types.ts b/packages/snap/src/utils/types.ts index d11631d..8ebd63c 100644 --- a/packages/snap/src/utils/types.ts +++ b/packages/snap/src/utils/types.ts @@ -1,34 +1,41 @@ -import * as t from 'io-ts' -import { CeloTransactionRequest } from '@celo-tools/celo-ethers-wrapper' +import * as t from 'io-ts'; +import { CeloTransactionRequest } from '@celo-tools/celo-ethers-wrapper'; import { BigNumber, BigNumberish, Bytes, ethers } from 'ethers'; export const BigNumberSchema: t.Type = new t.Type( - `BigNumberSchema`, - BigNumber.isBigNumber, - (unk: unknown, ctx: t.Context): t.Validation => { - if (BigNumber.isBigNumber(unk)) { - return t.success(unk as BigNumber) - } - return t.failure(unk, ctx) - }, - (bn: BigNumber) => bn -) + `BigNumberSchema`, + BigNumber.isBigNumber, + (unk: unknown, ctx: t.Context): t.Validation => { + if (BigNumber.isBigNumber(unk)) { + return t.success(unk as BigNumber); + } + return t.failure(unk, ctx); + }, + (bn: BigNumber) => bn, +); export const BytesSchema: t.Type = new t.Type( - `BytesSchema`, - ethers.utils.isBytes, - (unk: unknown, ctx: t.Context): t.Validation => { - if (ethers.utils.isBytes(unk)) { - return t.success(unk as Bytes) - } - return t.failure(unk, ctx) - }, - (bytes: Bytes) => bytes -) + `BytesSchema`, + ethers.utils.isBytes, + (unk: unknown, ctx: t.Context): t.Validation => { + if (ethers.utils.isBytes(unk)) { + return t.success(unk as Bytes); + } + return t.failure(unk, ctx); + }, + (bytes: Bytes) => bytes, +); -export const BigNumberishSchema: t.Type = t.union([t.string, t.number, t.bigint, BigNumberSchema, BytesSchema]) +export const BigNumberishSchema: t.Type = t.union([ + t.string, + t.number, + t.bigint, + BigNumberSchema, + BytesSchema, +]); -export const CeloTransactionRequestSchema: t.Type = t.partial({ +export const CeloTransactionRequestSchema: t.Type = + t.partial({ to: t.union([t.string, t.undefined]), from: t.union([t.string, t.undefined]), nonce: t.union([BigNumberishSchema, t.undefined]), @@ -43,30 +50,30 @@ export const CeloTransactionRequestSchema: t.Type = t.pa feeCurrency: t.union([t.string, t.undefined]), gatewayFeeRecipient: t.union([t.string, t.undefined]), gatewayFee: t.union([BigNumberishSchema, t.undefined]), -}) + }); -export interface RequestParams { - tx: CeloTransactionRequest -} +export type RequestParams = { + tx: CeloTransactionRequest; +}; export const RequestParamsSchema: t.Type = t.type({ - tx: CeloTransactionRequestSchema -}) + tx: CeloTransactionRequestSchema, +}); export type SortedOraclesRates = { - numerator: BigNumber - denominator: BigNumber -} + numerator: BigNumber; + denominator: BigNumber; +}; export type TokenInfo = { - address: string - value: BigNumber - balance?: BigNumber - rates?: SortedOraclesRates -} + address: string; + value: BigNumber; + balance?: BigNumber; + rates?: SortedOraclesRates; +}; -export interface KeyPair { - address: string; - privateKey: string; - publicKey: string; - } +export type KeyPair = { + address: string; + privateKey: string; + publicKey: string; +}; diff --git a/packages/snap/src/utils/utils.ts b/packages/snap/src/utils/utils.ts index 268defa..5b042c4 100644 --- a/packages/snap/src/utils/utils.ts +++ b/packages/snap/src/utils/utils.ts @@ -1,12 +1,20 @@ -import { BigNumber, constants } from "ethers"; +import { BigNumber, constants } from 'ethers'; +/** + * + * @param error + */ export function isInsufficientFundsError(error: any): boolean { - return error.hasOwnProperty('code') && error.code === 'INSUFFICIENT_FUNDS'; + return error.hasOwnProperty('code') && error.code === 'INSUFFICIENT_FUNDS'; } +/** + * + * @param value + */ export function handleNumber(value: any): BigNumber { - if (value === "0x" || !value) { - return constants.Zero; - } - return BigNumber.from(value); + if (value === '0x' || !value) { + return constants.Zero; + } + return BigNumber.from(value); }