Created
October 20, 2024 19:37
-
-
Save anastasiarods/60a581ca71d8f74ebba3bc838a29bcac to your computer and use it in GitHub Desktop.
Example of decoding EVM Gnosis Safe Calldata with Loop Decoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createPublicClient, http } from 'viem' | |
// Create a public client for the Ethereum Mainnet network | |
const getPublicClient = (chainId: number) => { | |
return { | |
client: createPublicClient({ | |
transport: http('https://rpc.ankr.com/eth'), | |
}), | |
} | |
} | |
import { | |
EtherscanStrategyResolver, | |
FourByteStrategyResolver, | |
VanillaAbiStore, | |
ContractABI, | |
} from '@3loop/transaction-decoder' | |
// Create an in-memory cache for the ABIs | |
const abiCache = new Map<string, ContractABI>() | |
const abiStore: VanillaAbiStore = { | |
// Define the strategies to use for fetching the ABIs | |
strategies: [ | |
EtherscanStrategyResolver({ | |
apikey: 'YourApiKeyToken', | |
}), | |
FourByteStrategyResolver(), | |
], | |
// Get the ABI from the cache | |
// Get it by contract address, event name or signature hash | |
get: async ({ address, event, signature }) => { | |
const value = abiCache.get(address) | |
if (value) { | |
return { | |
status: 'success', | |
result: value, | |
} | |
} else if (event) { | |
const value = abiCache.get(event) | |
if (value) { | |
return { | |
status: 'success', | |
result: value, | |
} | |
} | |
} else if (signature) { | |
const value = abiCache.get(signature) | |
if (value) { | |
return { | |
status: 'success', | |
result: value, | |
} | |
} | |
} | |
return { | |
status: 'empty', | |
result: null, | |
} | |
}, | |
// Set the ABI in the cache | |
// Store it by contract address, event name or signature hash | |
set: async (_key, value) => { | |
if (value.status === 'success') { | |
if (value.result.type === 'address') { | |
abiCache.set(value.result.address, value.result) | |
} else if (value.result.type === 'event') { | |
abiCache.set(value.result.event, value.result) | |
} else if (value.result.type === 'func') { | |
abiCache.set(value.result.signature, value.result) | |
} | |
} | |
}, | |
} | |
import type { ContractData, VanillaContractMetaStore } from '@3loop/transaction-decoder' | |
import { ERC20RPCStrategyResolver } from '@3loop/transaction-decoder' | |
// Create an in-memory cache for the contract meta-information | |
const contractMetaCache = new Map<string, ContractData>() | |
const contractMetaStore: VanillaContractMetaStore = { | |
// Define the strategies to use for fetching the contract meta-information | |
strategies: [ERC20RPCStrategyResolver], | |
// Get the contract meta-information from the cache | |
get: async ({ address, chainID }) => { | |
const key = `${address}-${chainID}`.toLowerCase() | |
const value = contractMetaCache.get(key) | |
if (value) { | |
return { | |
status: 'success', | |
result: value, | |
} | |
} | |
return { | |
status: 'empty', | |
result: null, | |
} | |
}, | |
// Set the contract meta-information in the cache | |
set: async ({ address, chainID }, result) => { | |
const key = `${address}-${chainID}`.toLowerCase() | |
if (result.status === 'success') { | |
contractMetaCache.set(key, result.result) | |
} | |
}, | |
} | |
import { TransactionDecoder } from '@3loop/transaction-decoder' | |
const decoder = new TransactionDecoder({ | |
getPublicClient: getPublicClient, | |
abiStore: abiStore, | |
contractMetaStore: contractMetaStore, | |
}) | |
async function main() { | |
try { | |
const decoded = await decoder.decodeCalldata({ | |
data: '0x8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006b2002d8880bcc0618dbcc5d516640015a69e28fdc406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003046a761202000000000000000000000000e3c408bd53c31c085a1746af401a4042954ff7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000e0d8be1dc2affefab9c066fd73a4b9788d3d3d4500000000000000000000000000000000000000000000000000064e5a6479f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001045f938ab87e466dca3d4953d42efc1fde996dcd7888622c9db2827bde3ecb169067e93c03124f4558edfed7819f454599a24aa75c8ba0aecb707bb6d7e8a265911f0ecd835bf25f1d74e4d89e30acb4176113c07d8a43a42712f4b1c6b658ff87f927e05f54ebf5b8c91ba843aefbb8e7d88ab73aaa66ede612e620d9847dc2260d1bbaa39fdd8469f14ea2342526d20e4458cbf9323a04ff6752acd302021067c84a7b59e4bc389954aa3a7daafe9b4a30fba791aab53266b9a7bbd78c31adba05571c29a581b2fa3ecb44c85cead416f6bfe0038b5d7e60202926e8e409c285a391d719858122d2f9a00e07417ac26b4c5370f0f6459332006edc20c65220acac58a32000000000000000000000000000000000000000000000000000000000002d8880bcc0618dbcc5d516640015a69e28fdc406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003046a761202000000000000000000000000e3c408bd53c31c085a1746af401a4042954ff7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000008b31d6018d2ee253379e98475c59c934549e62b00000000000000000000000000000000000000000000000000006651728988000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104946f3bb1ed2ba0acc722eec299e4fa02a741f6e5868f0643445f0ead1fe2b2f64cc28e5d2268f1f5f5e0239aaf1e4237be9bc67fb5bc1d8eae2c1d602089dcf720f7a65592538de69348f49784d27e7145ab96ffee198cab2d0c49f77a9cb415424881898c3df33e9318665e73e40ee66de96c5222d2b833edcf115a9b4a16cbd61c31c2a6240ac498822e1c6a61eb5a7271ad305f911985662b9a47e50249d88a7e53e187b542c9cf69dbccecc543fb76d7480a1d29c9db2a6fc81e04ecbfdf609b1bd3f85f39ff0f226493f3f5c8934507c92f24cd5b3365bd5e8bc4a4a2b23e6dcd28654caa13a0f5418f4cc642de81bff61d01b913883acf8c0794e94794a9405320000000000000000000000000000000000000000000000000000000000000000000000000000000000000', | |
chainID: 1, | |
contractAddress: '0x40A2aCCbd92BCA938b02010E17A5b8929b49130D', | |
}) | |
console.log(JSON.stringify(decoded, null, 2)) | |
} catch (e) { | |
console.error(JSON.stringify(e, null, 2)) | |
} | |
} | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment