From 47b8d1c11d6e6c1f79284f3d99b4abbef194bceb Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:51:38 +0200 Subject: [PATCH 1/9] docs: improved VM section (#190) * nextra upgrade * fix * deps update * improve doc * added "Get Started" section * w3vm: added doc example as code example * added "VM Setup" section * added "Execution" section * added state section * added utils section + improved godoc of utils * fixes * small tweak * updated receipt section * small fixes * fix --------- Co-authored-by: lmittmann --- README.md | 6 +- docs/components/DocLink.jsx | 11 +- docs/package-lock.json | 436 +++++++++++++++++++++-------------- docs/package.json | 10 +- docs/pages/rpc-extension.mdx | 2 +- docs/pages/rpc-overview.mdx | 2 +- docs/pages/vm-overview.mdx | 210 +++++++++++++++-- w3types/interfaces_test.go | 2 +- w3vm/receipt.go | 8 +- w3vm/util.go | 14 +- w3vm/vm.go | 17 +- w3vm/vm_test.go | 35 +++ 12 files changed, 519 insertions(+), 234 deletions(-) diff --git a/README.md b/README.md index a463340c..7daff0d8 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ if err := client.Call( #### Error Handling -If one ore more calls in a batch request fail, `Client.Call` returns an error of type [`w3.CallErrors`](https://pkg.go.dev/github.com/lmittmann/w3#CallErrors). +If one or more calls in a batch request fail, `Client.Call` returns an error of type [`w3.CallErrors`](https://pkg.go.dev/github.com/lmittmann/w3#CallErrors). **Example:** Check which RPC calls failed in a batch request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-CallErrors)) ```go @@ -144,7 +144,7 @@ A [`Func`](https://pkg.go.dev/github.com/lmittmann/w3#Func) can be used to * encode arguments to the contracts input data ([`Func.EncodeArgs`](https://pkg.go.dev/github.com/lmittmann/w3#Func.EncodeArgs)), * decode arguments from the contracts input data ([`Func.DecodeArgs`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeArgs)), and -* decode returns form the contracts output data ([`Func.DecodeReturns`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeReturns)). +* decode returns from the contracts output data ([`Func.DecodeReturns`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeReturns)). ### Utils @@ -240,7 +240,7 @@ func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCC // getTransactionBySenderAndNonceFactory implements the w3types.RPCCaller and // w3types.RPCCallerFactory interfaces. It stores the method parameters and -// the the reference to the return value. +// the reference to the return value. type getTransactionBySenderAndNonceFactory struct { // params sender common.Address diff --git a/docs/components/DocLink.jsx b/docs/components/DocLink.jsx index 144949c1..1bc3c2c0 100644 --- a/docs/components/DocLink.jsx +++ b/docs/components/DocLink.jsx @@ -12,11 +12,14 @@ const pkgNameToPath = { 'w3vm': 'github.com/lmittmann/w3/w3vm', } -export const DocLink = ({ title }) => { - let [pkg, comp] = title.split('.', 2) - let url = `https://pkg.go.dev/${pkgNameToPath[pkg]}#${comp}` +export const DocLink = ({ title, id }) => { + if (typeof id === 'undefined') { id = title } + let dotIndex = id.indexOf('.'); + let pkg = id.substring(0, dotIndex); + let comp = id.substring(dotIndex + 1); + return ( - + {title} ) diff --git a/docs/package-lock.json b/docs/package-lock.json index fa26dcf7..3320c0f5 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -5,16 +5,16 @@ "packages": { "": { "dependencies": { - "next": "^14.2.8", - "nextra": "3.0.0-alpha.36", - "nextra-theme-docs": "3.0.0-alpha.36", + "next": "^14.2.14", + "nextra": "3.0.0-alpha.40", + "nextra-theme-docs": "3.0.0-alpha.40", "react": "^18.3.1", "react-dom": "^18.3.1" }, "devDependencies": { "autoprefixer": "^10.4.20", - "postcss": "^8.4.45", - "tailwindcss": "^3.4.10" + "postcss": "^8.4.47", + "tailwindcss": "^3.4.13" } }, "node_modules/@alloc/quick-lru": { @@ -98,32 +98,32 @@ "license": "Apache-2.0" }, "node_modules/@floating-ui/core": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", - "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", "license": "MIT", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/react": { - "version": "0.26.23", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.23.tgz", - "integrity": "sha512-9u3i62fV0CFF3nIegiWiRDwOs7OW/KhSUJDNx2MkQM3LbE5zQOY01sL3nelcVBXvX7Ovvo3A49I8ql+20Wg/Hw==", + "version": "0.26.24", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz", + "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==", "license": "MIT", "dependencies": { - "@floating-ui/react-dom": "^2.1.1", - "@floating-ui/utils": "^0.2.7", + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", "tabbable": "^6.0.0" }, "peerDependencies": { @@ -132,9 +132,9 @@ } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", - "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.0.0" @@ -145,15 +145,15 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", "license": "MIT" }, "node_modules/@headlessui/react": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.5.tgz", - "integrity": "sha512-m3vzqwMTyDbgaNiSXQdrw8R4tRdnxVHHm4G/ZGS0TP6T8blEj3Ib1/zIJBzlvTXpBjTpd1DsUnRTonHyONMjSQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.8.tgz", + "integrity": "sha512-uajqVkAcVG/wHwG9Fh5PFMcFpf2VxM4vNRNKxRjuK009kePVur8LkuuygHfIE+2uZ7z7GnlTtYsyUe6glPpTLg==", "license": "MIT", "dependencies": { "@floating-ui/react": "^0.26.16", @@ -176,9 +176,9 @@ "license": "MIT" }, "node_modules/@iconify/utils": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.32.tgz", - "integrity": "sha512-LeifFZPPKu28O3AEDpYJNdEbvS4/ojAPyIW+pF/vUpJTYnbTiXUHkCh0bwgFRzKvdpb8H4Fbfd/742++MF4fPQ==", + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.33.tgz", + "integrity": "sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==", "license": "MIT", "dependencies": { "@antfu/install-pkg": "^0.4.0", @@ -572,15 +572,15 @@ } }, "node_modules/@next/env": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.8.tgz", - "integrity": "sha512-L44a+ynqkolyNBnYfF8VoCiSrjSZWgEHYKkKLGcs/a80qh7AkfVUD/MduVPgdsWZ31tgROR+yJRA0PZjSVBXWQ==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.14.tgz", + "integrity": "sha512-/0hWQfiaD5//LvGNgc8PjvyqV50vGK0cADYzaoOOGN8fxzBn3iAiaq3S0tCRnFBldq0LVveLcxCTi41ZoYgAgg==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.8.tgz", - "integrity": "sha512-1VrQlG8OzdyvvGZhGJFnaNE2P10Jjy/2FopnqbY0nSa/gr8If3iINxvOEW3cmVeoAYkmW0RsBazQecA2dBFOSw==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.14.tgz", + "integrity": "sha512-bsxbSAUodM1cjYeA4o6y7sp9wslvwjSkWw57t8DtC8Zig8aG8V6r+Yc05/9mDzLKcybb6EN85k1rJDnMKBd9Gw==", "cpu": [ "arm64" ], @@ -594,9 +594,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.8.tgz", - "integrity": "sha512-87t3I86rNRSOJB1gXIUzaQWWSWrkWPDyZGsR0Z7JAPtLeX3uUOW2fHxl7dNWD2BZvbvftctTQjgtfpp7nMtmWg==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.14.tgz", + "integrity": "sha512-cC9/I+0+SK5L1k9J8CInahduTVWGMXhQoXFeNvF0uNs3Bt1Ub0Azb8JzTU9vNCr0hnaMqiWu/Z0S1hfKc3+dww==", "cpu": [ "x64" ], @@ -610,9 +610,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.8.tgz", - "integrity": "sha512-ta2sfVzbOpTbgBrF9HM5m+U58dv6QPuwU4n5EX4LLyCJGKc433Z0D9h9gay/HSOjLEXJ2fJYrMP5JYYbHdxhtw==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.14.tgz", + "integrity": "sha512-RMLOdA2NU4O7w1PQ3Z9ft3PxD6Htl4uB2TJpocm+4jcllHySPkFaUIFacQ3Jekcg6w+LBaFvjSPthZHiPmiAUg==", "cpu": [ "arm64" ], @@ -626,9 +626,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.8.tgz", - "integrity": "sha512-+IoLTPK6Z5uIgDhgeWnQF5/o5GBN7+zyUNrs4Bes1W3g9++YELb8y0unFybS8s87ntAKMDl6jeQ+mD7oNwp/Ng==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.14.tgz", + "integrity": "sha512-WgLOA4hT9EIP7jhlkPnvz49iSOMdZgDJVvbpb8WWzJv5wBD07M2wdJXLkDYIpZmCFfo/wPqFsFR4JS4V9KkQ2A==", "cpu": [ "arm64" ], @@ -642,9 +642,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.8.tgz", - "integrity": "sha512-pO+hVXC+mvzUOQJJRG4RX4wJsRJ5BkURSf6dD6EjUXAX4Ml9es1WsEfkaZ4lcpmFzFvY47IkDaffks/GdCn9ag==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.14.tgz", + "integrity": "sha512-lbn7svjUps1kmCettV/R9oAvEW+eUI0lo0LJNFOXoQM5NGNxloAyFRNByYeZKL3+1bF5YE0h0irIJfzXBq9Y6w==", "cpu": [ "x64" ], @@ -658,9 +658,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.8.tgz", - "integrity": "sha512-bCat9izctychCtf3uL1nqHq31N5e1VxvdyNcBQflkudPMLbxVnlrw45Vi87K+lt1CwrtVayHqzo4ie0Szcpwzg==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.14.tgz", + "integrity": "sha512-7TcQCvLQ/hKfQRgjxMN4TZ2BRB0P7HwrGAYL+p+m3u3XcKTraUFerVbV3jkNZNwDeQDa8zdxkKkw2els/S5onQ==", "cpu": [ "x64" ], @@ -674,9 +674,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.8.tgz", - "integrity": "sha512-gbxfUaSPV7EyUobpavida2Hwi62GhSJaSg7iBjmBWoxkxlmETOD7U4tWt763cGIsyE6jM7IoNavq0BXqwdW2QA==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.14.tgz", + "integrity": "sha512-8i0Ou5XjTLEje0oj0JiI0Xo9L/93ghFtAUYZ24jARSeTMXLUx8yFIdhS55mTExq5Tj4/dC2fJuaT4e3ySvXU1A==", "cpu": [ "arm64" ], @@ -690,9 +690,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.8.tgz", - "integrity": "sha512-PUXzEzjTTlUh3b5VAn1nlpwvujTnuCMMwbiCnaTazoVlN1nA3kWjlmp42IfURA2N/nyrlVEw7pURa/o4Qxj1cw==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.14.tgz", + "integrity": "sha512-2u2XcSaDEOj+96eXpyjHjtVPLhkAFw2nlaz83EPeuK4obF+HmtDJHqgR1dZB7Gb6V/d55FL26/lYVd0TwMgcOQ==", "cpu": [ "ia32" ], @@ -706,9 +706,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.8.tgz", - "integrity": "sha512-EnPKv0ttq02E9/1KZ/8Dn7kuutv6hy1CKc0HlNcvzOQcm4/SQtvfws5gY0zrG9tuupd3HfC2L/zcTrnBhpjTuQ==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.14.tgz", + "integrity": "sha512-MZom+OvZ1NZxuRovKt1ApevjiUJTcU2PmdJKL66xUPaJeRywnbGGRWUlaAOwunD6dX+pm83vj979NTC8QXjGWg==", "cpu": [ "x64" ], @@ -864,29 +864,65 @@ } }, "node_modules/@shikijs/core": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.2.tgz", - "integrity": "sha512-XSVH5OZCvE4WLMgdoBqfPMYmGHGmCC3OgZhw0S7KcSi2XKZ+5oHGe71GFnTljgdOxvxx5WrRks6QoTLKrl1eAA==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.18.0.tgz", + "integrity": "sha512-VK4BNVCd2leY62Nm2JjyxtRLkyrZT/tv104O81eyaCjHq4Adceq2uJVFJJAIof6lT1mBwZrEo2qT/T+grv3MQQ==", "license": "MIT", "dependencies": { - "@shikijs/vscode-textmate": "^9.2.0", - "@types/hast": "^3.0.4" + "@shikijs/engine-javascript": "1.18.0", + "@shikijs/engine-oniguruma": "1.18.0", + "@shikijs/types": "1.18.0", + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.3" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.18.0.tgz", + "integrity": "sha512-qoP/aO/ATNwYAUw1YMdaip/YVEstMZEgrwhePm83Ll9OeQPuxDZd48szZR8oSQNQBT8m8UlWxZv8EA3lFuyI5A==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.18.0", + "@shikijs/vscode-textmate": "^9.2.2", + "oniguruma-to-js": "0.4.3" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.18.0.tgz", + "integrity": "sha512-B9u0ZKI/cud+TcmF8Chyh+R4V5qQVvyDOqXC2l2a4x73PBSBc6sZ0JRAX3eqyJswqir6ktwApUUGBYePdKnMJg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.18.0", + "@shikijs/vscode-textmate": "^9.2.2" } }, "node_modules/@shikijs/twoslash": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-1.16.2.tgz", - "integrity": "sha512-WzlCd7KnyfhBvGYb7tAbrxK1a9Rn2tQvAyv36RcggT418O3K5JRygiYAtf11qQjV1Q25TicczaosjPUVStFW0A==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-1.18.0.tgz", + "integrity": "sha512-nbv1vEiNlM9GbXpN0++5QiT2NdUbAJ6y8yBuMWIiT04dxD3tdl7Ud3TL6hAZ6CAwMGn5hRaN+2va2oN1Rsy1Ww==", "license": "MIT", "dependencies": { - "@shikijs/core": "1.16.2", - "twoslash": "^0.2.10" + "@shikijs/core": "1.18.0", + "@shikijs/types": "1.18.0", + "twoslash": "^0.2.11" + } + }, + "node_modules/@shikijs/types": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.18.0.tgz", + "integrity": "sha512-O9N36UEaGGrxv1yUrN2nye7gDLG5Uq0/c1LyfmxsvzNPqlHzWo9DI0A4+fhW2y3bGKuQu/fwS7EPdKJJCowcVA==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4" } }, "node_modules/@shikijs/vscode-textmate": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.0.tgz", - "integrity": "sha512-5FinaOp6Vdh/dl4/yaOTh0ZeKch+rYS8DUb38V3GMKYVkdqzxw53lViRKUYkVILRiVQT7dcPC7VvAKOR73zVtQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.2.tgz", + "integrity": "sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==", "license": "MIT" }, "node_modules/@swc/counter": { @@ -906,12 +942,12 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.10.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.7.tgz", - "integrity": "sha512-yeP+M0G8D+15ZFPivpuQ5hoM4Fa/PzERBx8P8EGcfEsXX3JOb9G9UUrqc47ZXAxvK+YqzM9T5qlJUYUFOwCZJw==", + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.8.tgz", + "integrity": "sha512-VbzbVGSsZlQktyLrP5nxE+vE1ZR+U0NFAWPbJLoG2+DKPwd2D7dVICTVIIaYlJqX1ZCEnYDbaOpmMwbsyhBoIA==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.10.7" + "@tanstack/virtual-core": "3.10.8" }, "funding": { "type": "github", @@ -923,9 +959,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.10.7", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.7.tgz", - "integrity": "sha512-ND5dfsU0n9F4gROzwNNDJmg6y8n9pI8YWxtgbfJ5UcNn7Hx+MxEXtXcQ189tS7sh8pmCObgz2qSiyRKTZxT4dg==", + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.8.tgz", + "integrity": "sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==", "license": "MIT", "funding": { "type": "github", @@ -974,9 +1010,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "license": "MIT" }, "node_modules/@types/estree-jsx": { @@ -1034,16 +1070,16 @@ } }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", "license": "MIT", "peer": true }, "node_modules/@types/react": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", - "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", + "version": "18.3.9", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.9.tgz", + "integrity": "sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ==", "license": "MIT", "peer": true, "dependencies": { @@ -1097,9 +1133,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -1301,9 +1337,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -1321,8 +1357,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, @@ -1355,9 +1391,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001657", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001657.tgz", - "integrity": "sha512-DPbJAlP8/BAXy3IgiWmZKItubb3TYGP0WscQQlVGIfT4s/YlFYVuJgyOsQNP7rJRChx/qdMeLJQJP0Sgg2yjNA==", + "version": "1.0.30001663", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", + "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==", "funding": [ { "type": "opencollective", @@ -2154,12 +2190,12 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2242,9 +2278,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.14", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.14.tgz", - "integrity": "sha512-bEfPECb3fJ15eaDnu9LEJ2vPGD6W1vt7vZleSVyFhYuMIKm3vz/g9lt7IvEzgdwj58RjbPKUF2rXTCN/UW47tQ==", + "version": "1.5.28", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz", + "integrity": "sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw==", "dev": true, "license": "ISC" }, @@ -2746,9 +2782,9 @@ } }, "node_modules/hast-util-from-html": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.2.tgz", - "integrity": "sha512-HwOHwxdt2zC5KQ/CNoybBntRook2zJvfZE/u5/Ap7aLPe22bDqen7KwGkOqOyzL5zIqKwiYX/OTtE0FWgr6XXA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2878,6 +2914,29 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", @@ -2906,18 +2965,18 @@ } }, "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", - "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", "license": "MIT" }, "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.7.tgz", - "integrity": "sha512-uSjr59G5u6fbxUfKbb8GcqMGT3Xs9v5IbPkjb0S16GyOeBLAzSRK0CixBv5YrYvzO6TDLzIS6QCn78tkqWngPw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", "license": "MIT", "dependencies": { - "inline-style-parser": "0.2.3" + "inline-style-parser": "0.2.4" } }, "node_modules/hast-util-to-parse5": { @@ -3609,9 +3668,9 @@ } }, "node_modules/mdast-util-mdx-expression": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", - "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -3747,9 +3806,9 @@ } }, "node_modules/mermaid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.1.0.tgz", - "integrity": "sha512-ICexrwPRzU1USFcpAdrVVGjCwEajD+iAwu2LVHi59D6VbXmFhwfB9TbCL3sA6NBR1tl5qUjQSAOdc9lOKlXnEw==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.2.1.tgz", + "integrity": "sha512-F8TEaLVVyxTUmvKswVFyOkjPrlJA5h5vNR1f7ZnSWSpqxgEZG1hggtn/QCa7znC28bhlcrNh10qYaIiill7q4A==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.0.1", @@ -4592,9 +4651,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/mz": { @@ -4628,12 +4687,12 @@ } }, "node_modules/next": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.8.tgz", - "integrity": "sha512-EyEyJZ89r8C5FPlS/401AiF3O8jeMtHIE+bLom9MwcdWJJFBgRl+MR/2VgO0v5bI6tQORNY0a0DR5sjpFNrjbg==", + "version": "14.2.14", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.14.tgz", + "integrity": "sha512-Q1coZG17MW0Ly5x76shJ4dkC23woLAhhnDnw+DfTc7EpZSGuWrlsZ3bZaO8t6u1Yu8FVfhkqJE+U8GC7E0GLPQ==", "license": "MIT", "dependencies": { - "@next/env": "14.2.8", + "@next/env": "14.2.14", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -4648,15 +4707,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.8", - "@next/swc-darwin-x64": "14.2.8", - "@next/swc-linux-arm64-gnu": "14.2.8", - "@next/swc-linux-arm64-musl": "14.2.8", - "@next/swc-linux-x64-gnu": "14.2.8", - "@next/swc-linux-x64-musl": "14.2.8", - "@next/swc-win32-arm64-msvc": "14.2.8", - "@next/swc-win32-ia32-msvc": "14.2.8", - "@next/swc-win32-x64-msvc": "14.2.8" + "@next/swc-darwin-arm64": "14.2.14", + "@next/swc-darwin-x64": "14.2.14", + "@next/swc-linux-arm64-gnu": "14.2.14", + "@next/swc-linux-arm64-musl": "14.2.14", + "@next/swc-linux-x64-gnu": "14.2.14", + "@next/swc-linux-x64-musl": "14.2.14", + "@next/swc-win32-arm64-msvc": "14.2.14", + "@next/swc-win32-ia32-msvc": "14.2.14", + "@next/swc-win32-x64-msvc": "14.2.14" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -4716,9 +4775,9 @@ } }, "node_modules/nextra": { - "version": "3.0.0-alpha.36", - "resolved": "https://registry.npmjs.org/nextra/-/nextra-3.0.0-alpha.36.tgz", - "integrity": "sha512-c6WeiMwgisQgF+dllj8bF8WI4jU4NvDBqqOqM9vstAbveMl95eBNUQ9QOdvfpwNasX9Azf/uPG3PNarMKoZYQg==", + "version": "3.0.0-alpha.40", + "resolved": "https://registry.npmjs.org/nextra/-/nextra-3.0.0-alpha.40.tgz", + "integrity": "sha512-8/JfKASmsCV2mEH0eaJRfvxjwq5XSuUDAP8ByqQScgHQGqiZkmUYkve3zElm/n0v1e3Ksjs3wdz1YMKO4eqYXA==", "license": "MIT", "dependencies": { "@headlessui/react": "^2.1.2", @@ -4765,9 +4824,9 @@ } }, "node_modules/nextra-theme-docs": { - "version": "3.0.0-alpha.36", - "resolved": "https://registry.npmjs.org/nextra-theme-docs/-/nextra-theme-docs-3.0.0-alpha.36.tgz", - "integrity": "sha512-uFixrxEmmqTGOPNvHSDY6IuoxxgqajE9WV6OlU3YnWnDuA3WDDlvYF13S1YIN8FSal+YILH1wuE9KFCSvv7GqA==", + "version": "3.0.0-alpha.40", + "resolved": "https://registry.npmjs.org/nextra-theme-docs/-/nextra-theme-docs-3.0.0-alpha.40.tgz", + "integrity": "sha512-xpCDCm+DFQr/hw/8uLx7w7u02pM6odaNK1Y+GzUIXgmRZtpaifvX6UpvdsAPu4Tvkhy1LbfPw9Qtcl9QM9e9Hg==", "license": "MIT", "dependencies": { "@headlessui/react": "^2.1.2", @@ -4781,7 +4840,7 @@ }, "peerDependencies": { "next": ">=13", - "nextra": "3.0.0-alpha.36", + "nextra": "3.0.0-alpha.40", "react": ">=16.13.1", "react-dom": ">=16.13.1" } @@ -4879,6 +4938,18 @@ "node": ">= 6" } }, + "node_modules/oniguruma-to-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", + "integrity": "sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==", + "license": "MIT", + "dependencies": { + "regex": "^4.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -5102,9 +5173,9 @@ } }, "node_modules/postcss": { - "version": "8.4.45", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", - "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "dev": true, "funding": [ { @@ -5123,8 +5194,8 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -5355,6 +5426,12 @@ "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", "license": "MIT" }, + "node_modules/regex": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.2.tgz", + "integrity": "sha512-kK/AA3A9K6q2js89+VMymcboLOlF5lZRCYJv3gzszXFHBr6kO6qLGzbm+UIugBEV8SMMKCTR59txoY6ctRHYVw==", + "license": "MIT" + }, "node_modules/rehype-katex": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", @@ -5599,9 +5676,9 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", - "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -5844,13 +5921,16 @@ } }, "node_modules/shiki": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.16.2.tgz", - "integrity": "sha512-gSym0hZf5a1U0iDPsdoOAZbvoi+e0c6c3NKAi03FoSLTm7oG20tum29+gk0wzzivOasn3loxfGUPT+jZXIUbWg==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.18.0.tgz", + "integrity": "sha512-8jo7tOXr96h9PBQmOHVrltnETn1honZZY76YA79MHheGQg55jBvbm9dtU+MI5pjC5NJCFuA6rvVTLVeSW5cE4A==", "license": "MIT", "dependencies": { - "@shikijs/core": "1.16.2", - "@shikijs/vscode-textmate": "^9.2.0", + "@shikijs/core": "1.18.0", + "@shikijs/engine-javascript": "1.18.0", + "@shikijs/engine-oniguruma": "1.18.0", + "@shikijs/types": "1.18.0", + "@shikijs/vscode-textmate": "^9.2.2", "@types/hast": "^3.0.4" } }, @@ -5889,9 +5969,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -6183,9 +6263,9 @@ "license": "MIT" }, "node_modules/tailwindcss": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", - "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", + "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", "dev": true, "license": "MIT", "dependencies": { @@ -6335,28 +6415,28 @@ "license": "0BSD" }, "node_modules/twoslash": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.2.10.tgz", - "integrity": "sha512-EBnFbGSD7VtPYCYe8tnx5wDzTfQ2wDS10J89BnTr97Zu2+wRD/CskNLPvvDEZofb37mLSce/YuTP8GgGj+vSOg==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.2.11.tgz", + "integrity": "sha512-392Qkcu5sD2hROLZ+XPywChreDGJ8Yu5nnK/Moxfti/R39q0Q39MaV7iHjz92B5qucyjsQFnKMdYIzafX5T8dg==", "license": "MIT", "dependencies": { "@typescript/vfs": "^1.6.0", - "twoslash-protocol": "0.2.10" + "twoslash-protocol": "0.2.11" }, "peerDependencies": { "typescript": "*" } }, "node_modules/twoslash-protocol": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.2.10.tgz", - "integrity": "sha512-9sFHqPUexUPKAZM2e0dbAh0Hwkxd5fqSKWWMQ8Ah+O6MeYEUDGuWUUw5aUfS6veAqo+24VfV3xF0Vj0ZbH7x3Q==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.2.11.tgz", + "integrity": "sha512-rp+nkOWbKfJnBTDZtnIaBGjnU+4CaMhqu6db2UU7byU96rH8X4hao4BOxYw6jdZc85Lhv5pOfcjgfHeQyLzndQ==", "license": "MIT" }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "license": "Apache-2.0", "peer": true, "bin": { @@ -6897,9 +6977,9 @@ } }, "node_modules/zod-validation-error": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.3.1.tgz", - "integrity": "sha512-uFzCZz7FQis256dqw4AhPQgD6f3pzNca/Zh62RNELavlumQB3nDIUFbF5JQfFLcMbO1s02Q7Xg/gpcOBlEnYZA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", "license": "MIT", "engines": { "node": ">=18.0.0" diff --git a/docs/package.json b/docs/package.json index 680ef6ad..a186972c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,15 +5,15 @@ "build": "next build" }, "dependencies": { - "next": "^14.2.8", - "nextra": "3.0.0-alpha.36", - "nextra-theme-docs": "3.0.0-alpha.36", + "next": "^14.2.14", + "nextra": "3.0.0-alpha.40", + "nextra-theme-docs": "3.0.0-alpha.40", "react": "^18.3.1", "react-dom": "^18.3.1" }, "devDependencies": { "autoprefixer": "^10.4.20", - "postcss": "^8.4.45", - "tailwindcss": "^3.4.10" + "postcss": "^8.4.47", + "tailwindcss": "^3.4.13" } } diff --git a/docs/pages/rpc-extension.mdx b/docs/pages/rpc-extension.mdx index 91a229da..655f1d7c 100644 --- a/docs/pages/rpc-extension.mdx +++ b/docs/pages/rpc-extension.mdx @@ -15,7 +15,7 @@ func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCC // getTransactionBySenderAndNonceFactory implements the w3types.RPCCaller and // w3types.RPCCallerFactory interfaces. It stores the method parameters and -// the the reference to the return value. +// the reference to the return value. type getTransactionBySenderAndNonceFactory struct { // params sender common.Address diff --git a/docs/pages/rpc-overview.mdx b/docs/pages/rpc-overview.mdx index 70515c81..39f25aa3 100644 --- a/docs/pages/rpc-overview.mdx +++ b/docs/pages/rpc-overview.mdx @@ -1,6 +1,6 @@ # RPC Client - is a blazing fast RPC client build on top of `go-ethereum/rpc.Client`. It is designed for batch requests and easy extendibility. + is a blazing fast RPC client, built on top of `go-ethereum/rpc.Client`. It is designed for **batch requests** and **easy extendibility**. ## Get Started diff --git a/docs/pages/vm-overview.mdx b/docs/pages/vm-overview.mdx index 63758741..cd28242b 100644 --- a/docs/pages/vm-overview.mdx +++ b/docs/pages/vm-overview.mdx @@ -1,46 +1,206 @@ # VM - is a high-level EVM environment with a simple but powerful API to simulate EVM execution, test Smart Contracts, or trace transactions. It supports Mainnet state forking via RPC and state caching for faster testing. + is a super simple to use Ethereum Virtual Machine (EVM), built on top of `go-ethereum/core/vm.EVM`. It supports **tracing**, **state forking** via RPC, and can be used for simulation, debugging EVM execution, or testing Smart Contracts. -**Example:** Simulate an Uniswap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) +* **State forking** via RPC, or custom state fetchers enable transaction simulations or Smart Contract tests on live, or historic chain state. +* **Tracing** of EVM execution is supported via `go-ethereum/core/tracing.Hooks`. + + +## Get Started + + + +### Create a VM Instance + +Create a VM instance, that forks the latest Mainnet state. ```go -// 1. Create a VM that forks the Mainnet state from the latest block, -// disables the base fee, and has a fake WETH balance and approval for the router +client, err := w3.Dial("https://rpc.ankr.com/eth") +if err != nil { + // ... +} +defer client.Close() + vm, err := w3vm.New( w3vm.WithFork(client, nil), w3vm.WithNoBaseFee(), - w3vm.WithState(w3types.State{ - addrWETH: {Storage: w3types.Storage{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), - }}, - }), ) if err != nil { - // handle error + // ... } +``` + +### Simulate a Simple Message + +Transfer ETH from the zero address to a random recipient. + +```go +recipient := w3vm.RandA() -// 2. Simulate a Uniswap v3 swap receipt, err := vm.Apply(&w3types.Message{ - From: addrEOA, - To: &addrRouter, - Func: funcExactInput, - Args: []any{&ExactInputParams{ - Path: encodePath(addrWETH, 500, addrUNI), - Recipient: addrEOA, - Deadline: big.NewInt(time.Now().Unix()), - AmountIn: w3.I("1 ether"), - AmountOutMinimum: w3.Big0, - }}, + From: common.Address{}, + To: &recipient, + Value: w3.I("1 ether"), }) +if err != nil { + // ... +} +``` + +### Verify the Recipient's Balance + +Verify the recipient's balance after the applied message. + +```go +balance, err := vm.Balance(recipient) +if err != nil { + // ... +} + +fmt.Printf("Balance: %s ETH\n", w3.FromWei(balance, 18)) +// Output: Balance: 1 ETH +``` + + + + +## Setup + +A new VM instance is created using the `w3vm.New` function, which accepts various options to customize the VM behavior. + +* `WithChainConfig(cfg *params.ChainConfig)`: Sets the chain configuration. If not set, the VM falls back to the Mainnet configuration. +* `WithNoBaseFee()`: Forces the EIP-1559 base fee to 0. +* `WithBlockContext(ctx *vm.BlockContext)`: Sets the block context for the VM. +* `WithHeader(header *types.Header)`: Sets the block context for the VM based on the given header. +* `WithState(state w3types.State)`: Sets the pre state of the VM. If used with `WithFork`, the pre state overrides the forked state. +* `WithStateDB(db *state.StateDB)`: Sets the state database for the VM, that is usually a snapshot obtained from `VM.Snapshot`. +* `WithFork(client *w3.Client, blockNumber *big.Int)`: Forks state from a live Ethereum client at a specific block number. +* `WithFetcher(fetcher Fetcher)`: Sets the fetcher for the VM. +* `WithTB(tb testing.TB)`: Enables persistent state caching when used together with `WithFork`. + + +## Execution + +Messages represent transactions or contract calls that can be executed by the VM. + +All execution methods support **tracing** via `go-ethereum/core/tracing.Hooks`. [Learn more ➔](/vm-tracing) + +### `Apply` Method + + applies a `w3types.Message` to the VM and returns a `Receipt`. If the execution doesn't revert, the VM's underlying state may change. + +#### Example: Apply a Message + +```go +msg := &w3types.Message{ + From: addrSender, + To: &addrRecipient, + Value: w3.I("1 ether"), + Gas: 21000, +} + +receipt, err := vm.Apply(msg) +if err != nil { + // ... +} +fmt.Printf("Gas Used: %d\n", receipt.GasUsed) +``` + +### `ApplyTx` Method + + is like `Apply`, but takes a `types.Transaction` instead of a message. The given transaction is converted to a message internally, using a signer, that is derived from the VM's chain configuration and fork block. + +### `Call` Method + + is like `Apply`, but any state changes during execution are reverted in the end, so the VM's state is never modified. + +#### Example: Call `balanceOf` + +```go +funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") + +msg := &w3types.Message{ + To: &addrToken, + Func: funcBalanceOf, + Args: []any{addrOwner}, +} + +receipt, err := vm.Call(msg) if err != nil { // handle error } -// 3. Decode output amount -var amountOut *big.Int -if err := receipt.DecodeReturns(&amountOut); err != nil { +var balance *big.Int +if err := receipt.DecodeReturns(&balance); err != nil { // handle error } +fmt.Printf("Balance: %s\n", balance) ``` + +### `CallFunc` Method + + is a helper, that greatly simplifies common usage of `Call`. It is designed analogues to the `eth.CallFunc` RPC client method. + +#### Example: Call `balanceOf` with `CallFunc` + +This is a simplified version of the [Call `balanceOf`](#example-call-balanceof) example. + +```go +funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") + +var balance *big.Int +err := vm.CallFunc(addrToken, funcBalanceOf, addrOwner).Returns(&balance) +if err != nil { + // handle error +} +fmt.Printf("Balance: %s\n", balance) +``` + +### `Receipt` Type + +The `Receipt` struct contains the result of an executed message. + +#### Fields + +* `GasUsed uint64`: Gas used for executing the message. +* `GasRefund uint64`: Gas refunded after executing the message. +* `Logs []*types.Log`: Logs emitted while executing the message. +* `Output []byte`: Output of the executed message. +* `ContractAddress *common.Address`: Address of the created contract, if any. +* `Err error`: Execution error, if any. + +#### Methods + +* `DecodeReturns(returns ...any) error`: Decodes the return values. This method only works, if the executed message had `w3types.Message.Func` set. + + +## State + +The VM provides methods to read, and write account state. + +### Reading State + +* `vm.Balance(addr common.Address) (*big.Int, error)`: Returns the balance of the given address. +* `vm.Nonce(addr common.Address) (uint64, error)`: Returns the nonce of the given address. +* `vm.Code(addr common.Address) ([]byte, error)`: Returns the code of the given address. +* `vm.StorageAt(addr common.Address, slot common.Hash) (common.Hash, error)`: Returns the state of the given address at the given storage slot. + + +An error only can only occur, if the VM fails to fetch state via a `w3vm.Fetcher`. Thus, it is safe to ignore the error, if no state fetcher is used by the VM. + + +### Writing State + +* `vm.SetBalance(addr common.Address, balance *big.Int)`: Sets the balance of the given address. +* `vm.SetNonce(addr common.Address, nonce uint64)`: Sets the nonce of the given address. +* `vm.SetCode(addr common.Address, code []byte)`: Sets the code of the given address. +* `vm.SetStorageAt(addr common.Address, slot common.Hash, value common.Hash)`: Sets the state of the given address at the give storage slot. + + +## Helper + +* `w3vm.RandA() common.Address`: Returns a random address. +* `WETHBalanceSlot(addr common.Address) common.Hash`: Returns the storage slot that stores the WETH balance of the given address. +* `WETHAllowanceSlot(owner, spender common.Address) common.Hash`: Returns the storage slot that stores the WETH allowance of the given owner to the spender. +* `Slot(pos, key common.Hash) common.Hash`: Returns the storage slot of a mapping with the given position and key. +* `Slot2(pos, key, key2 common.Hash) common.Hash`: Returns the storage slot of a double mapping with the given position and keys. diff --git a/w3types/interfaces_test.go b/w3types/interfaces_test.go index 398e784c..b15cf42a 100644 --- a/w3types/interfaces_test.go +++ b/w3types/interfaces_test.go @@ -19,7 +19,7 @@ func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCC // getTransactionBySenderAndNonceFactory implements the w3types.RPCCaller and // w3types.RPCCallerFactory interfaces. It stores the method parameters and -// the the reference to the return value. +// the reference to the return value. type getTransactionBySenderAndNonceFactory struct { // params sender common.Address diff --git a/w3vm/receipt.go b/w3vm/receipt.go index a00ab3ec..350cfd28 100644 --- a/w3vm/receipt.go +++ b/w3vm/receipt.go @@ -16,11 +16,11 @@ type Receipt struct { GasUsed uint64 // Gas used for executing the message GasRefund uint64 // Gas refunded after executing the message - Logs []*types.Log // Logs emitted by the message - Output []byte // Output bytes of the applied message - ContractAddress *common.Address // Contract address created by a contract creation transaction + Logs []*types.Log // Logs emitted while executing the message + Output []byte // Output of the executed message + ContractAddress *common.Address // Address of the created contract, if any - Err error // Revert reason + Err error // Execution error, if any } // DecodeReturns is like [w3types.Func.DecodeReturns], but returns [ErrMissingFunc] diff --git a/w3vm/util.go b/w3vm/util.go index 1b78439f..88482a41 100644 --- a/w3vm/util.go +++ b/w3vm/util.go @@ -28,8 +28,8 @@ func RandA() (addr common.Address) { } var ( - weth9BalancePos = common.BigToHash(big.NewInt(3)) - weth9AllowancePos = common.BigToHash(big.NewInt(4)) + weth9BalancePos = common.BytesToHash([]byte{3}) + weth9AllowancePos = common.BytesToHash([]byte{4}) ) // WETHBalanceSlot returns the storage slot that stores the WETH balance of @@ -39,18 +39,26 @@ func WETHBalanceSlot(addr common.Address) common.Hash { } // WETHAllowanceSlot returns the storage slot that stores the WETH allowance -// of the given owner and spender. +// of the given owner to the spender. func WETHAllowanceSlot(owner, spender common.Address) common.Hash { return Slot2(weth9AllowancePos, common.BytesToHash(owner[:]), common.BytesToHash(spender[:])) } // Slot returns the storage slot of a mapping with the given position and key. +// +// Slot follows the Solidity storage layout for: +// +// mapping(bytes32 => bytes32) func Slot(pos, key common.Hash) common.Hash { return crypto.Keccak256Hash(key[:], pos[:]) } // Slot2 returns the storage slot of a double mapping with the given position // and keys. +// +// Slot2 follows the Solidity storage layout for: +// +// mapping(bytes32 => mapping(bytes32 => bytes32)) func Slot2(pos, key, key2 common.Hash) common.Hash { return crypto.Keccak256Hash( key2[:], diff --git a/w3vm/vm.go b/w3vm/vm.go index 9455c977..fe7b33fc 100644 --- a/w3vm/vm.go +++ b/w3vm/vm.go @@ -77,8 +77,8 @@ func New(opts ...Option) (*VM, error) { return vm, nil } -// Apply the given message to the VM and return its receipt. Multiple tracing hooks -// can be given to trace the execution of the message. +// Apply the given message to the VM, and return its receipt. Multiple tracing hooks +// may be given to trace the execution of the message. func (vm *VM) Apply(msg *w3types.Message, hooks ...*tracing.Hooks) (*Receipt, error) { return vm.apply(msg, false, joinHooks(hooks)) } @@ -158,15 +158,15 @@ func (v *VM) apply(msg *w3types.Message, isCall bool, hooks *tracing.Hooks) (*Re return receipt, receipt.Err } -// Call calls the given message on the VM and returns a receipt. Any state changes -// of a call are reverted. Multiple tracing hooks can be passed to trace the execution +// Call the given message on the VM, and returns its receipt. Any state changes +// of a call are reverted. Multiple tracing hooks may be given to trace the execution // of the message. func (vm *VM) Call(msg *w3types.Message, hooks ...*tracing.Hooks) (*Receipt, error) { return vm.apply(msg, true, joinHooks(hooks)) } // CallFunc is a utility function for [VM.Call] that calls the given function -// on the given contract address with the given arguments and parses the +// on the given contract address with the given arguments and decodes the // output into the given returns. // // Example: @@ -477,9 +477,8 @@ func WithState(state w3types.State) Option { return func(vm *VM) { vm.opts.preState = state } } -// WithStateDB sets the state DB for the VM. -// -// The state DB can originate from a snapshot of the VM. +// WithStateDB sets the state DB for the VM, that is usually a snapshot +// obtained from [VM.Snapshot]. func WithStateDB(db *state.StateDB) Option { return func(vm *VM) { vm.db = db @@ -505,7 +504,7 @@ func WithFork(client *w3.Client, blockNumber *big.Int) Option { } } -// WithHeader sets the block context for the VM based on the given header +// WithHeader sets the block context for the VM based on the given header. func WithHeader(header *types.Header) Option { return func(vm *VM) { vm.opts.header = header } } diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index 19a39824..dc9fbd1c 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -811,6 +811,41 @@ func BenchmarkTransferWETH9(b *testing.B) { func ptr[T any](t T) *T { return &t } +func ExampleVM_transferEthFromZeroAddress() { + client, err := w3.Dial("https://rpc.ankr.com/eth") + if err != nil { + // handle error + } + defer client.Close() + + vm, err := w3vm.New( + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + ) + if err != nil { + // handle error + } + + recipient := w3vm.RandA() + + _, err = vm.Apply(&w3types.Message{ + From: common.Address{}, + To: &recipient, + Value: w3.I("1 ether"), + }) + if err != nil { + // handle error + } + + balance, err := vm.Balance(recipient) + if err != nil { + // handle error + } + + fmt.Printf("Balance: %s ETH\n", w3.FromWei(balance, 18)) + // Output: Balance: 1 ETH +} + func ExampleVM() { var ( addrEOA = w3.A("0x000000000000000000000000000000000000c0Fe") From f9caa4811d395280dc27087fcd6e193443975cca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:25:06 +0200 Subject: [PATCH 2/9] build(deps): bump golang.org/x/time from 0.6.0 to 0.7.0 (#196) * build(deps): bump golang.org/x/time from 0.6.0 to 0.7.0 Bumps [golang.org/x/time](https://github.com/golang/time) from 0.6.0 to 0.7.0. - [Commits](https://github.com/golang/time/compare/v0.6.0...v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/time dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * examples: `go mod tidy` * fix --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lmittmann --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 08c8ff2c..7b05dc64 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -32,6 +32,6 @@ require ( golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect - golang.org/x/time v0.6.0 // indirect + golang.org/x/time v0.7.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index fb2f0638..367f8eb9 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -133,8 +133,8 @@ golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/go.mod b/go.mod index 026446f3..9477a3c1 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/ethereum/go-ethereum v1.14.8 github.com/google/go-cmp v0.6.0 github.com/holiman/uint256 v1.3.1 - golang.org/x/time v0.6.0 + golang.org/x/time v0.7.0 ) require ( diff --git a/go.sum b/go.sum index 640138d2..11b7d8cc 100644 --- a/go.sum +++ b/go.sum @@ -519,8 +519,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= From 16a1ce200347ff7df5ba78155a42af39ee0a920a Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:25:26 +0200 Subject: [PATCH 3/9] w3vm/hooks: Added CallTracer-Hook (#192) * internal/fourbyte: init * w3vm/hooks: init call tracer * internal/fourbyte: added more funcs * examples: `go mod tidy` * internal/fourbyte: init event generation * internal/fourbyte: added `Event(..)` * w3vm/hooks: improved revert reason decoding * w3vm/hooks: fix * added more funcs and events * internal/fourbyte: added precompiles * added more functions * added functions * added opcode rendering * added option `ShowStaticcall` * `go mod tidy` * examples fix deps * added comments * dropped option --------- Co-authored-by: lmittmann --- examples/go.sum | 8 +- go.mod | 10 +- go.sum | 18 +- internal/fourbyte/events.go | 14 + internal/fourbyte/events.txt | 7 + internal/fourbyte/fourbyte.go | 38 +++ internal/fourbyte/funcs.go | 202 ++++++++++++++ internal/fourbyte/funcs.txt | 194 ++++++++++++++ internal/fourbyte/gen.go | 272 +++++++++++++++++++ w3vm/hooks/call_tracer.go | 487 ++++++++++++++++++++++++++++++++++ 10 files changed, 1241 insertions(+), 9 deletions(-) create mode 100644 internal/fourbyte/events.go create mode 100644 internal/fourbyte/events.txt create mode 100644 internal/fourbyte/fourbyte.go create mode 100644 internal/fourbyte/funcs.go create mode 100644 internal/fourbyte/funcs.txt create mode 100644 internal/fourbyte/gen.go create mode 100644 w3vm/hooks/call_tracer.go diff --git a/examples/go.sum b/examples/go.sum index 367f8eb9..f6ecb976 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -82,8 +82,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= @@ -103,8 +103,8 @@ github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuI github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= diff --git a/go.mod b/go.mod index 9477a3c1..4a30df66 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/lmittmann/w3 go 1.22 require ( + github.com/charmbracelet/lipgloss v0.13.0 github.com/ethereum/go-ethereum v1.14.8 github.com/google/go-cmp v0.6.0 github.com/holiman/uint256 v1.3.1 @@ -14,10 +15,12 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.12.2 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charmbracelet/x/ansi v0.1.4 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -43,16 +46,19 @@ require ( github.com/klauspost/compress v1.16.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.12.0 // indirect github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/supranational/blst v0.3.11 // indirect diff --git a/go.sum b/go.sum index 11b7d8cc..a4c85b69 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -64,6 +66,10 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= +github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= +github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= +github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -251,13 +257,15 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -273,6 +281,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= @@ -318,8 +328,9 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -502,6 +513,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/internal/fourbyte/events.go b/internal/fourbyte/events.go new file mode 100644 index 00000000..20d065cb --- /dev/null +++ b/internal/fourbyte/events.go @@ -0,0 +1,14 @@ +// Code generated by "go generate"; DO NOT EDIT. +package fourbyte + +import "github.com/lmittmann/w3" + +var events = map[[32]byte]*w3.Event{ + {0x0d, 0x36, 0x48, 0xbd, 0x0f, 0x6b, 0xa8, 0x01, 0x34, 0xa3, 0x3b, 0xa9, 0x27, 0x5a, 0xc5, 0x85, 0xd9, 0xd3, 0x15, 0xf0, 0xad, 0x83, 0x55, 0xcd, 0xde, 0xfd, 0xe3, 0x1a, 0xfa, 0x28, 0xd0, 0xe9}: w3.MustNewEvent("PairCreated(address indexed token0, address indexed token1, address pair, uint256)"), + {0x1c, 0x41, 0x1e, 0x9a, 0x96, 0xe0, 0x71, 0x24, 0x1c, 0x2f, 0x21, 0xf7, 0x72, 0x6b, 0x17, 0xae, 0x89, 0xe3, 0xca, 0xb4, 0xc7, 0x8b, 0xe5, 0x0e, 0x06, 0x2b, 0x03, 0xa9, 0xff, 0xfb, 0xba, 0xd1}: w3.MustNewEvent("Sync(uint112 reserve0, uint112 reserve1)"), + {0x4c, 0x20, 0x9b, 0x5f, 0xc8, 0xad, 0x50, 0x75, 0x8f, 0x13, 0xe2, 0xe1, 0x08, 0x8b, 0xa5, 0x6a, 0x56, 0x0d, 0xff, 0x69, 0x0a, 0x1c, 0x6f, 0xef, 0x26, 0x39, 0x4f, 0x4c, 0x03, 0x82, 0x1c, 0x4f}: w3.MustNewEvent("Mint(address indexed sender, uint256 amount0, uint256 amount1)"), + {0x8c, 0x5b, 0xe1, 0xe5, 0xeb, 0xec, 0x7d, 0x5b, 0xd1, 0x4f, 0x71, 0x42, 0x7d, 0x1e, 0x84, 0xf3, 0xdd, 0x03, 0x14, 0xc0, 0xf7, 0xb2, 0x29, 0x1e, 0x5b, 0x20, 0x0a, 0xc8, 0xc7, 0xc3, 0xb9, 0x25}: w3.MustNewEvent("Approval(address indexed owner, address indexed spender, uint256 value)"), + {0xd7, 0x8a, 0xd9, 0x5f, 0xa4, 0x6c, 0x99, 0x4b, 0x65, 0x51, 0xd0, 0xda, 0x85, 0xfc, 0x27, 0x5f, 0xe6, 0x13, 0xce, 0x37, 0x65, 0x7f, 0xb8, 0xd5, 0xe3, 0xd1, 0x30, 0x84, 0x01, 0x59, 0xd8, 0x22}: w3.MustNewEvent("Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to)"), + {0xdc, 0xcd, 0x41, 0x2f, 0x0b, 0x12, 0x52, 0x81, 0x9c, 0xb1, 0xfd, 0x33, 0x0b, 0x93, 0x22, 0x4c, 0xa4, 0x26, 0x12, 0x89, 0x2b, 0xb3, 0xf4, 0xf7, 0x89, 0x97, 0x6e, 0x6d, 0x81, 0x93, 0x64, 0x96}: w3.MustNewEvent("Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to)"), + {0xdd, 0xf2, 0x52, 0xad, 0x1b, 0xe2, 0xc8, 0x9b, 0x69, 0xc2, 0xb0, 0x68, 0xfc, 0x37, 0x8d, 0xaa, 0x95, 0x2b, 0xa7, 0xf1, 0x63, 0xc4, 0xa1, 0x16, 0x28, 0xf5, 0x5a, 0x4d, 0xf5, 0x23, 0xb3, 0xef}: w3.MustNewEvent("Transfer(address indexed from, address indexed to, uint256 value)"), +} diff --git a/internal/fourbyte/events.txt b/internal/fourbyte/events.txt new file mode 100644 index 00000000..aafbafe8 --- /dev/null +++ b/internal/fourbyte/events.txt @@ -0,0 +1,7 @@ +Approval(address indexed owner, address indexed spender, uint256 value) +Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to) +Mint(address indexed sender, uint256 amount0, uint256 amount1) +PairCreated(address indexed token0, address indexed token1, address pair, uint256) +Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to) +Sync(uint112 reserve0, uint112 reserve1) +Transfer(address indexed from, address indexed to, uint256 value) diff --git a/internal/fourbyte/fourbyte.go b/internal/fourbyte/fourbyte.go new file mode 100644 index 00000000..2d1d28c8 --- /dev/null +++ b/internal/fourbyte/fourbyte.go @@ -0,0 +1,38 @@ +//go:generate go run gen.go + +package fourbyte + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" +) + +var ( + precompile1 = w3.MustNewFunc("ecRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)", "address") + precompile2 = w3.MustNewFunc("keccak(bytes)", "bytes32") + precompile3 = w3.MustNewFunc("ripemd160(bytes)", "bytes32") + precompile4 = w3.MustNewFunc("identity(bytes)", "bytes") + + addr1 = common.BytesToAddress([]byte{0x01}) + addr2 = common.BytesToAddress([]byte{0x02}) + addr3 = common.BytesToAddress([]byte{0x03}) + addr4 = common.BytesToAddress([]byte{0x04}) +) + +func Function(sig [4]byte, addr common.Address) (fn *w3.Func, isPrecompile bool) { + switch addr { + case addr1: + return precompile1, true + case addr2: + return precompile2, true + case addr3: + return precompile3, true + case addr4: + return precompile4, true + } + return functions[sig], false +} + +func Event(topic0 [32]byte, addr common.Address) *w3.Event { + return events[topic0] +} diff --git a/internal/fourbyte/funcs.go b/internal/fourbyte/funcs.go new file mode 100644 index 00000000..e9205ec0 --- /dev/null +++ b/internal/fourbyte/funcs.go @@ -0,0 +1,202 @@ +// Code generated by "go generate"; DO NOT EDIT. +package fourbyte + +import "github.com/lmittmann/w3" + +var functions = map[[4]byte]*w3.Func{ + {0x01, 0xff, 0xc9, 0xa7}: w3.MustNewFunc("supportsInterface(bytes4)", "bool"), + {0x02, 0x2c, 0x0d, 0x9f}: w3.MustNewFunc("swap(uint256 amount0Out, uint256 amount1Out, address to, bytes data)", ""), + {0x02, 0x75, 0x1c, 0xec}: w3.MustNewFunc("removeLiquidityETH(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline)", "uint256 amountToken, uint256 amountETH"), + {0x02, 0xcc, 0x25, 0x0d}: w3.MustNewFunc("isSolver(address)", "bool"), + {0x05, 0x4d, 0x50, 0xd4}: w3.MustNewFunc("getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)", "uint256 amountOut"), + {0x05, 0x8a, 0x62, 0x8f}: w3.MustNewFunc("setAuthorizer(address newAuthorizer)", ""), + {0x06, 0xfd, 0xde, 0x03}: w3.MustNewFunc("name()", "string"), + {0x07, 0x21, 0x1e, 0xf7}: w3.MustNewFunc("get_dy_underlying(int128 i, int128 j, uint256 amount)", "uint256"), + {0x08, 0x18, 0x12, 0xfc}: w3.MustNewFunc("getApproved(uint256 tokenId)", "address operator"), + {0x08, 0xc3, 0x79, 0xa0}: w3.MustNewFunc("Error(string)", ""), + {0x09, 0x02, 0xf1, 0xac}: w3.MustNewFunc("getReserves()", "uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast"), + {0x09, 0x5e, 0xa7, 0xb3}: w3.MustNewFunc("approve(address spender, uint256 amount)", "bool success"), + {0x0c, 0x03, 0x3b, 0x9b}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline, bytes data)", "int256 amount0, int256 amount1"), + {0x0d, 0x58, 0xb1, 0xdb}: w3.MustNewFunc("transferFrom((address from, address to, uint160 amount, address token)[] transferDetails)", ""), + {0x0d, 0xfe, 0x16, 0x81}: w3.MustNewFunc("token0()", "address"), + {0x0f, 0x5a, 0x6e, 0xfa}: w3.MustNewFunc("getInternalBalance(address user, address[] tokens)", "uint256[]"), + {0x12, 0x49, 0xc5, 0x8b}: w3.MustNewFunc("mint()", ""), + {0x12, 0x8a, 0xcb, 0x08}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes data)", "int256 amount0, int256 amount1"), + {0x13, 0xd7, 0x9a, 0x0b}: w3.MustNewFunc("settle(address[] tokens, uint256[] clearingPrices, (uint256 sellTokenIndex, uint256 buyTokenIndex, address receiver, uint256 sellAmount, uint256 buyAmount, uint32 validTo, bytes32 appData, uint256 feeAmount, uint256 flags, uint256 executedAmount, bytes signature)[] trades, (address target, uint256 value, bytes callData)[][3] interactions)", ""), + {0x15, 0x0b, 0x7a, 0x02}: w3.MustNewFunc("onERC721Received(address operator, address from, uint256 tokenId, bytes data)", "bytes4"), + {0x16, 0x26, 0xba, 0x7e}: w3.MustNewFunc("isValidSignature(bytes32 hash, bytes data)", "bytes4"), + {0x17, 0x32, 0x60, 0xeb}: w3.MustNewFunc("settleInternal((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (uint256[] increasedBuyAmounts, uint16 curFillPercent) makerData)", ""), + {0x17, 0x7e, 0x80, 0x2f}: w3.MustNewFunc("ERC721InsufficientApproval(address operator, uint256 tokenId)", ""), + {0x18, 0x16, 0x0d, 0xdd}: w3.MustNewFunc("totalSupply()", "uint256"), + {0x18, 0xcb, 0xaf, 0xe5}: w3.MustNewFunc("swapExactTokensForETH(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)", "uint256[] amounts"), + {0x18, 0xfd, 0xd0, 0x6b}: w3.MustNewFunc("getGrossAmountFromTotalSold(uint256 totalAmount)", "uint256"), + {0x1a, 0x68, 0x65, 0x02}: w3.MustNewFunc("liquidity()", "uint128"), + {0x1c, 0x56, 0x03, 0x05}: w3.MustNewFunc("claimMintRewardAndShare(address other, uint256 pct)", ""), + {0x1f, 0x00, 0xca, 0x74}: w3.MustNewFunc("getAmountsIn(uint256 amountOut, address[] path)", "uint256[] amounts"), + {0x20, 0xc1, 0x3b, 0x0b}: w3.MustNewFunc("isValidSignature(bytes data, bytes signature)", "bytes4"), + {0x21, 0x4a, 0x6f, 0xe2}: w3.MustNewFunc("accumulateReward(uint32 currTimestamp)", ""), + {0x21, 0x95, 0x99, 0x5c}: w3.MustNewFunc("removeLiquidityWithPermit(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s)", "uint256 amountA, uint256 amountB"), + {0x23, 0xa6, 0x9e, 0x75}: w3.MustNewFunc("pancakeV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes data)", ""), + {0x23, 0xb8, 0x72, 0xdd}: w3.MustNewFunc("transferFrom(address from, address to, uint256 amount)", "bool success"), + {0x24, 0x85, 0x6b, 0xc3}: w3.MustNewFunc("execute(bytes commands, bytes[] inputs)", ""), + {0x24, 0x8a, 0x9c, 0xa3}: w3.MustNewFunc("getRoleAdmin(bytes32 role)", "bytes32"), + {0x28, 0xb2, 0xa7, 0x96}: w3.MustNewFunc("settleInternalWithPermitsSignatures((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline) takerPermitsInfo, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (uint256[] increasedBuyAmounts, uint16 curFillPercent) makerData)", ""), + {0x2a, 0x2d, 0x80, 0xd1}: w3.MustNewFunc("permit(address owner, ((address token, uint160 amount, uint48 expiration, uint48 nonce)[] details, address spender, uint256 sigDeadline) permitBatch, bytes signature)", ""), + {0x2e, 0x1a, 0x7d, 0x4d}: w3.MustNewFunc("withdraw(uint256)", ""), + {0x2f, 0x2f, 0xf1, 0x5d}: w3.MustNewFunc("grantRole(bytes32 role, address account)", ""), + {0x31, 0x3c, 0xe5, 0x67}: w3.MustNewFunc("decimals()", "uint8"), + {0x35, 0x93, 0x56, 0x4c}: w3.MustNewFunc("execute(bytes commands, bytes[] inputs, uint256 deadline)", ""), + {0x36, 0x44, 0xe5, 0x15}: w3.MustNewFunc("DOMAIN_SEPARATOR()", "bytes32"), + {0x36, 0x56, 0x8a, 0xbe}: w3.MustNewFunc("renounceRole(bytes32 role, address account)", ""), + {0x36, 0xc7, 0x85, 0x16}: w3.MustNewFunc("transferFrom(address from, address to, uint160 amount, address token)", ""), + {0x38, 0x50, 0xc7, 0xbd}: w3.MustNewFunc("slot0()", "(uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)"), + {0x38, 0xe9, 0x92, 0x2e}: w3.MustNewFunc("setSwapFeePercentage(uint256)", ""), + {0x38, 0xed, 0x17, 0x39}: w3.MustNewFunc("swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)", "uint256[] amounts"), + {0x39, 0x47, 0x47, 0xc5}: w3.MustNewFunc("exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy, bool use_eth)", ""), + {0x39, 0x50, 0x93, 0x51}: w3.MustNewFunc("increaseAllowance(address spender, uint256 addedValue)", "bool success"), + {0x3a, 0x98, 0xef, 0x39}: w3.MustNewFunc("totalShares()", "uint256"), + {0x3d, 0xf0, 0x21, 0x24}: w3.MustNewFunc("exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)", ""), + {0x3f, 0x44, 0x28, 0x64}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline, bytes data, uint256 trackingCode)", "int256 amount0, int256 amount1"), + {0x40, 0xc1, 0x0f, 0x19}: w3.MustNewFunc("mint(address to, uint256 amount)", ""), + {0x40, 0xfb, 0x07, 0xa0}: w3.MustNewFunc("buyAsset(uint256 minAmount, address receiver)", "uint256, uint256"), + {0x42, 0x84, 0x2e, 0x0e}: w3.MustNewFunc("safeTransferFrom(address from, address to, uint256 tokenId)", ""), + {0x42, 0x96, 0x6c, 0x68}: w3.MustNewFunc("burn(uint256)", ""), + {0x45, 0xd6, 0x49, 0x4d}: w3.MustNewFunc("getBuyFee(uint256 grossAmount)", "uint256"), + {0x46, 0x09, 0x85, 0xe8}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 trackingCode)", "int256 amount0, int256 amount1"), + {0x46, 0x0d, 0xd9, 0x49}: w3.MustNewFunc("settleBatch((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers)[] orders, (uint8 type, bytes signatureBytes)[] signatures, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline)[] takersPermitsInfo, (bool result, address to, uint256 value, bytes data)[] interactions, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle)[] hooks, (address balanceRecipient, uint16[] curFillPercents, bool[] takersPermitsUsage, bool transferExactAmounts) solverData)", ""), + {0x46, 0x14, 0x13, 0x19}: w3.MustNewFunc("feeGrowthGlobal1X128()", "uint256"), + {0x48, 0x5c, 0xc9, 0x55}: w3.MustNewFunc("initialize(address token0, address token1)", ""), + {0x49, 0x0e, 0x6c, 0xbc}: w3.MustNewFunc("flash(address recipient, uint256 amount0, uint256 amount1, bytes data)", ""), + {0x49, 0x3f, 0x4f, 0x74}: w3.MustNewFunc("get_address(uint256 idx)", "address"), + {0x4a, 0x25, 0xd9, 0x4a}: w3.MustNewFunc("swapTokensForExactETH(uint256 amountOut, uint256 amountInMax, address[] path, address to, uint256 deadline)", "uint256[] amounts"), + {0x4a, 0x2a, 0xb3, 0xbe}: w3.MustNewFunc("get_y(uint256 ANN, uint256 gamma, uint256[3] x, uint256 D, uint256 i)", "uint256[2]"), + {0x4c, 0x84, 0xc1, 0xc8}: w3.MustNewFunc("wrapAll()", ""), + {0x52, 0xbb, 0xbe, 0x29}: w3.MustNewFunc("swap((bytes32 poolId, uint8 swapKind, address assetIn, address assetOut, uint256 amount, bytes data) singleSwap, (address sender, bool fromInternalBalance, address recipient, bool toInternalBalance) funds, uint256 limit, uint256 deadline)", "uint256"), + {0x52, 0xc7, 0xf8, 0xdc}: w3.MustNewFunc("claimMintReward()", ""), + {0x54, 0x0d, 0x49, 0x18}: w3.MustNewFunc("lmPool()", "address"), + {0x54, 0xfd, 0x4d, 0x50}: w3.MustNewFunc("version()", "uint256"), + {0x57, 0x4f, 0x2b, 0xa3}: w3.MustNewFunc("allPairsLength()", "uint256"), + {0x59, 0x09, 0xc0, 0xd5}: w3.MustNewFunc("price0CumulativeLast()", "uint256"), + {0x59, 0x21, 0xc8, 0xe0}: w3.MustNewFunc("burnAfterSeize(uint256 amount)", "uint256"), + {0x5a, 0x3d, 0x54, 0x93}: w3.MustNewFunc("price1CumulativeLast()", "uint256"), + {0x5b, 0x08, 0xba, 0x18}: w3.MustNewFunc("ERC721InvalidOperator(address operator)", ""), + {0x5b, 0x0d, 0x59, 0x84}: w3.MustNewFunc("removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s)", "uint256 amountETH"), + {0x5b, 0x41, 0xb9, 0x08}: w3.MustNewFunc("exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy)", ""), + {0x5b, 0xcc, 0xb4, 0xc4}: w3.MustNewFunc("claimMintRewardAndStake(uint256 pct, uint256 term)", ""), + {0x5c, 0x11, 0xd7, 0x95}: w3.MustNewFunc("swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)", ""), + {0x5c, 0x60, 0xda, 0x1b}: w3.MustNewFunc("implementation()", "address"), + {0x5c, 0x97, 0x5a, 0xbb}: w3.MustNewFunc("paused()", "bool"), + {0x5d, 0xed, 0x74, 0xa5}: w3.MustNewFunc("getGhoPriceInAsset(uint256 ghoAmount, bool roundUp)", "uint256"), + {0x5e, 0x0d, 0x44, 0x3f}: w3.MustNewFunc("get_dy(int128 i, int128 j, uint256 amount)", "uint256"), + {0x60, 0x52, 0x97, 0xe1}: w3.MustNewFunc("seize()", "uint256"), + {0x63, 0x52, 0x21, 0x1e}: w3.MustNewFunc("ownerOf(uint256 tokenId)", "address"), + {0x64, 0x28, 0x3d, 0x7b}: w3.MustNewFunc("ERC721IncorrectOwner(address sender, uint256 tokenId, address owner)", ""), + {0x64, 0xa0, 0xae, 0x92}: w3.MustNewFunc("ERC721InvalidReceiver(address receiver)", ""), + {0x69, 0x62, 0xf8, 0x45}: w3.MustNewFunc("mint_relative(address to, uint256 frac)", "uint256"), + {0x6d, 0x54, 0x33, 0xe6}: w3.MustNewFunc("max(uint256, uint256)", "uint256"), + {0x70, 0xa0, 0x82, 0x31}: w3.MustNewFunc("balanceOf(address)", "uint256"), + {0x71, 0x50, 0x18, 0xa6}: w3.MustNewFunc("renounceOwnership()", ""), + {0x72, 0x84, 0xe4, 0x16}: w3.MustNewFunc("description()", "string"), + {0x73, 0xc6, 0xac, 0x6e}: w3.MustNewFunc("ERC721InvalidSender(address sender)", ""), + {0x74, 0x64, 0xfc, 0x3d}: w3.MustNewFunc("kLast()", "uint256"), + {0x75, 0x19, 0xab, 0x50}: w3.MustNewFunc("updatedAt()", "uint256"), + {0x75, 0x4b, 0x76, 0xb3}: w3.MustNewFunc("get_p(uint256[3] xp, uint256 D, uint256[2] A_gamma)", "uint256[2]"), + {0x75, 0xd3, 0x9e, 0xcb}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline)", "int256 amount0, int256 amount1"), + {0x79, 0x1a, 0xc9, 0x47}: w3.MustNewFunc("swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)", ""), + {0x79, 0xcc, 0x67, 0x90}: w3.MustNewFunc("burnFrom(address to, uint256 value)", "bool"), + {0x7a, 0xe2, 0xb5, 0xc7}: w3.MustNewFunc("min(uint256, uint256)", "uint256"), + {0x7b, 0x04, 0x72, 0xf0}: w3.MustNewFunc("stake(uint256 amount, uint256 term)", ""), + {0x7b, 0x12, 0xe0, 0x09}: w3.MustNewFunc("newton_D(uint256 ANN, uint256 gamma, uint256[3] x_unsorted, uint256 K0_prev)", "uint256"), + {0x7d, 0x10, 0xd1, 0x1f}: w3.MustNewFunc("transferFromAccounts((address account, address token, uint256 amount, bytes32 balance)[])", ""), + {0x7e, 0x27, 0x32, 0x89}: w3.MustNewFunc("ERC721NonexistentToken(uint256 tokenId)", ""), + {0x7f, 0xf3, 0x6a, 0xb5}: w3.MustNewFunc("swapExactETHForTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline)", "uint256[] amounts"), + {0x81, 0xd1, 0x8d, 0x87}: w3.MustNewFunc("wad_exp(int256 power)", "uint256"), + {0x85, 0xf8, 0xc2, 0x59}: w3.MustNewFunc("getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut)", "uint256 amountIn"), + {0x87, 0x52, 0x8f, 0x13}: w3.MustNewFunc("settle((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, (bool result, address to, uint256 value, bytes data)[] interactions, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (address balanceRecipient, uint16 curFillPercent) solverData)", ""), + {0x88, 0x03, 0xdb, 0xee}: w3.MustNewFunc("swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] path, address to, uint256 deadline)", "uint256[] amounts"), + {0x89, 0xc6, 0x2b, 0x64}: w3.MustNewFunc("ERC721InvalidOwner(address owner)", ""), + {0x8d, 0xa5, 0xcb, 0x5b}: w3.MustNewFunc("owner()", "address"), + {0x90, 0x10, 0xd0, 0x7c}: w3.MustNewFunc("getRoleMember(bytes32 role, uint256 index)", "address"), + {0x91, 0xd1, 0x48, 0x54}: w3.MustNewFunc("hasRole(bytes32 role, address account)", "bool"), + {0x92, 0x7d, 0xa1, 0x05}: w3.MustNewFunc("allowance(address user, address token, address spender)", "uint160 amount, uint48 expiration, uint48 nonce"), + {0x94, 0x28, 0x0d, 0x62}: w3.MustNewFunc("ERC20InvalidSpender(address spender)", ""), + {0x94, 0x5b, 0xce, 0xc9}: w3.MustNewFunc("batchSwap(uint8 swapKind, (bytes32 poolId, uint256 assetInIndex, uint256 assetOutIndex, uint256 amount, bytes data)[] swaps, address[] assets, (address sender, bool fromInternalBalance, address recipient, bool toInternalBalance) funds, int256[] limits, uint256 deadline)", "int256[]"), + {0x95, 0x4c, 0x1c, 0x0d}: w3.MustNewFunc("buyAssetWithSig(address originator, uint256 minAmount, address receiver, uint256 deadline, bytes signature)", "uint256, uint256"), + {0x95, 0x9d, 0x6d, 0x29}: w3.MustNewFunc("getSellFee(uint256 grossAmount)", "uint256"), + {0x95, 0xd8, 0x9b, 0x41}: w3.MustNewFunc("symbol()", "string"), + {0x96, 0xc6, 0xfd, 0x1e}: w3.MustNewFunc("ERC20InvalidSender(address sender)", ""), + {0x9a, 0x6f, 0xc8, 0xf5}: w3.MustNewFunc("getRoundData(uint80 roundId)", "uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound"), + {0x9b, 0xe2, 0xa8, 0x84}: w3.MustNewFunc("canPerform(bytes32 actionId, address account, address where)", "bool"), + {0x9d, 0xc2, 0x9f, 0xac}: w3.MustNewFunc("burn(address user, uint256 amount)", ""), + {0xa0, 0x71, 0x2d, 0x68}: w3.MustNewFunc("mint(uint256)", ""), + {0xa1, 0x6f, 0x5f, 0xd2}: w3.MustNewFunc("cumulativeSum()", "uint256"), + {0xa2, 0x2c, 0xb4, 0x65}: w3.MustNewFunc("setApprovalForAll(address operator, bool approved)", ""), + {0xa2, 0x3b, 0xa0, 0x9c}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline, uint256 trackingCode)", "int256 amount0, int256 amount1"), + {0xa2, 0x62, 0x90, 0x4b}: w3.MustNewFunc("get_registry()", "address"), + {0xa4, 0x57, 0xc2, 0xd7}: w3.MustNewFunc("decreaseAllowance(address spender, uint256 subtractedValue)", "bool success"), + {0xa4, 0x98, 0x46, 0x33}: w3.MustNewFunc("crossLmTick(int24 tick, bool zeroForOne)", ""), + {0xa4, 0xa2, 0x1f, 0xa2}: w3.MustNewFunc("getGrossAmountFromTotalBought(uint256 totalAmount)", "uint256"), + {0xa6, 0x41, 0x7e, 0xd6}: w3.MustNewFunc("exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy)", ""), + {0xa7, 0xb7, 0x8c, 0x3c}: w3.MustNewFunc("getAssetPriceInGho(uint256 assetAmount, bool roundUp)", "uint256"), + {0xa9, 0x05, 0x9c, 0xbb}: w3.MustNewFunc("transfer(address to, uint256 amount)", "bool success"), + {0xa9, 0xfb, 0xf5, 0x1f}: w3.MustNewFunc("ERC721InvalidApprover(address approver)", ""), + {0xaa, 0x44, 0x3a, 0xc0}: w3.MustNewFunc("sellAsset(uint256 maxAmount, address receiver)", "uint256, uint256"), + {0xaa, 0xab, 0xad, 0xc5}: w3.MustNewFunc("getAuthorizer()", "address"), + {0xad, 0x5c, 0x46, 0x48}: w3.MustNewFunc("WETH()", "address"), + {0xad, 0x61, 0x5d, 0xec}: w3.MustNewFunc("quote(uint256 amountA, uint256 reserveA, uint256 reserveB)", "uint256 amountB"), + {0xae, 0x5b, 0x25, 0x40}: w3.MustNewFunc("setApp(bytes32 namespace, bytes32 appId, address app)", ""), + {0xaf, 0x29, 0x79, 0xeb}: w3.MustNewFunc("removeLiquidityETHSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline)", "uint256 amountETH"), + {0xb0, 0x34, 0x43, 0x04}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes data, uint256 trackingCode)", "int256 amount0, int256 amount1"), + {0xb6, 0xf9, 0xde, 0x95}: w3.MustNewFunc("swapExactETHForTokensSupportingFeeOnTransferTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline)", ""), + {0xb8, 0x8d, 0x4f, 0xde}: w3.MustNewFunc("safeTransferFrom(address from, address to, uint256 tokenId, bytes data)", ""), + {0xba, 0x9a, 0x7a, 0x56}: w3.MustNewFunc("MINIMUM_LIQUIDITY()", "uint256"), + {0xba, 0xa2, 0xab, 0xde}: w3.MustNewFunc("removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline)", "uint256 amountA, uint256 amountB"), + {0xba, 0xd1, 0xdc, 0x26}: w3.MustNewFunc("geometric_mean(uint256[3] x)", "uint256"), + {0xbc, 0x25, 0xcf, 0x77}: w3.MustNewFunc("skim(address to)", ""), + {0xbe, 0x00, 0xbb, 0xd8}: w3.MustNewFunc("getApp(bytes32 namespace, bytes32 appId)", "address"), + {0xc3, 0x1b, 0x8d, 0x7a}: w3.MustNewFunc("swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96)", "int256 amount0, int256 amount1"), + {0xc4, 0x5a, 0x01, 0x55}: w3.MustNewFunc("factory()", "address"), + {0xc6, 0x61, 0x06, 0x57}: w3.MustNewFunc("coins(uint256 i)", "address"), + {0xc8, 0x7b, 0x56, 0xdd}: w3.MustNewFunc("tokenURI(uint256 tokenId)", "string"), + {0xc9, 0xc6, 0x53, 0x96}: w3.MustNewFunc("createPair(address tokenA, address tokenB)", "address pair"), + {0xca, 0x15, 0xc8, 0x73}: w3.MustNewFunc("getRoleMemberCount(bytes32 role)", "uint256"), + {0xca, 0xb4, 0x6b, 0xc6}: w3.MustNewFunc("setSwapFreeze(bool enable)", ""), + {0xce, 0x7d, 0x65, 0x03}: w3.MustNewFunc("exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy, bool use_eth, address receiver)", "uint256"), + {0xce, 0xa9, 0xd2, 0x6f}: w3.MustNewFunc("rescueTokens(address token, address to, uint256 amount)", ""), + {0xd0, 0x6c, 0xa6, 0x1f}: w3.MustNewFunc("getAmountsOut(uint256 amountIn, address[] path)", "uint256[] amounts"), + {0xd0, 0xc9, 0x3a, 0x7c}: w3.MustNewFunc("tickSpacing()", "int24"), + {0xd0, 0xe3, 0x0d, 0xb0}: w3.MustNewFunc("deposit()", ""), + {0xd2, 0x12, 0x20, 0xa7}: w3.MustNewFunc("token1()", "address"), + {0xd5, 0x05, 0xac, 0xcf}: w3.MustNewFunc("permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)", ""), + {0xd5, 0x47, 0x74, 0x1f}: w3.MustNewFunc("revokeRole(bytes32 role, address account)", ""), + {0xdd, 0x62, 0xed, 0x3e}: w3.MustNewFunc("allowance(address owner, address spender)", "uint256"), + {0xdd, 0xc1, 0xf5, 0x9d}: w3.MustNewFunc("exchange(int128 i, int128 j, uint256 dx, uint256 min_dy, address receiver)", ""), + {0xdd, 0xca, 0x3f, 0x43}: w3.MustNewFunc("fee()", "uint24"), + {0xde, 0x28, 0x73, 0x59}: w3.MustNewFunc("acl()", "address"), + {0xde, 0xd9, 0x38, 0x2a}: w3.MustNewFunc("removeLiquidityETHWithPermit(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s)", "uint256 amountToken, uint256 amountETH"), + {0xe4, 0x49, 0x02, 0x2e}: w3.MustNewFunc("uniswapV3Swap(uint256 amount, uint256 minReturn, uint256[] pools)", "uint256 returnAmount"), + {0xe4, 0x50, 0xd3, 0x8c}: w3.MustNewFunc("ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)", ""), + {0xe6, 0x02, 0xdf, 0x05}: w3.MustNewFunc("ERC20InvalidApprover(address approver)", ""), + {0xe6, 0xa4, 0x39, 0x05}: w3.MustNewFunc("getPair(address tokenA, address tokenB)", "address pair"), + {0xe8, 0xe3, 0x37, 0x00}: w3.MustNewFunc("addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline)", "uint256 amountA, uint256 amountB, uint256 liquidity"), + {0xe9, 0x85, 0xe9, 0xc5}: w3.MustNewFunc("isApprovedForAll(address owner, address operator)", "bool"), + {0xeb, 0x8d, 0x21, 0x16}: w3.MustNewFunc("transferTokens((address from, address receiver, address[] tokens, uint256[] amounts, uint256[] nftIds, bytes tokenTransferTypes, uint16 fillPercent) transferData)", ""), + {0xec, 0x44, 0x2f, 0x05}: w3.MustNewFunc("ERC20InvalidReceiver(address receiver)", ""), + {0xec, 0x98, 0x37, 0x76}: w3.MustNewFunc("settleWithPermitsSignatures((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline) takerPermitsInfo, (bool result, address to, uint256 value, bytes data)[] interactions, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (address balanceRecipient, uint16 curFillPercent) solverData)", ""), + {0xf2, 0xfd, 0xe3, 0x8b}: w3.MustNewFunc("transferOwnership(address newOwner)", ""), + {0xf3, 0x05, 0x83, 0x99}: w3.MustNewFunc("feeGrowthGlobal0X128()", "uint256"), + {0xf3, 0x05, 0xd7, 0x19}: w3.MustNewFunc("addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline)", "uint256 amountToken, uint256 amountETH, uint256 liquidity"), + {0xf4, 0x2c, 0x56, 0xc2}: w3.MustNewFunc("cbrt(uint256 x)", "uint256"), + {0xf4, 0x93, 0xca, 0x70}: w3.MustNewFunc("sellAssetWithSig(address originator, uint256 maxAmount, address receiver, uint256 deadline, bytes signature)", "uint256, uint256"), + {0xf8, 0x51, 0xa4, 0x40}: w3.MustNewFunc("admin()", "address"), + {0xfa, 0x18, 0x04, 0x2d}: w3.MustNewFunc("reduction_coefficient(uint256[3] x, uint256 fee_gamma)", "uint256"), + {0xfa, 0x46, 0x1e, 0x33}: w3.MustNewFunc("uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes data)", ""), + {0xfa, 0x6e, 0x67, 0x1d}: w3.MustNewFunc("setRelayerApproval(address sender, address relayer, bool approved)", ""), + {0xfb, 0x3b, 0xdb, 0x41}: w3.MustNewFunc("swapETHForExactTokens(uint256 amountOut, address[] path, address to, uint256 deadline)", "uint256[] amounts"), + {0xfb, 0x8f, 0x41, 0xb2}: w3.MustNewFunc("ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)", ""), + {0xfc, 0x0c, 0x54, 0x6a}: w3.MustNewFunc("token()", "address"), + {0xfd, 0xef, 0x91, 0x06}: w3.MustNewFunc("hasPermission(address who, address where, bytes32 what, bytes how)", "bool"), + {0xfe, 0xaf, 0x96, 0x8c}: w3.MustNewFunc("latestRoundData()", "uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound"), + {0xfe, 0xc9, 0x0d, 0x72}: w3.MustNewFunc("hasApprovedRelayer(address user, address relayer)", "bool"), + {0xff, 0xf6, 0xca, 0xe9}: w3.MustNewFunc("sync()", ""), +} diff --git a/internal/fourbyte/funcs.txt b/internal/fourbyte/funcs.txt new file mode 100644 index 00000000..a8b6ce33 --- /dev/null +++ b/internal/fourbyte/funcs.txt @@ -0,0 +1,194 @@ +accumulateReward(uint32 currTimestamp) +acl() address +addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) uint256 amountA, uint256 amountB, uint256 liquidity +addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) uint256 amountToken, uint256 amountETH, uint256 liquidity +admin() address +allowance(address owner, address spender) uint256 +allowance(address user, address token, address spender) uint160 amount, uint48 expiration, uint48 nonce +allPairsLength() uint256 +approve(address spender, uint256 amount) bool success +balanceOf(address) uint256 +batchSwap(uint8 swapKind, (bytes32 poolId, uint256 assetInIndex, uint256 assetOutIndex, uint256 amount, bytes data)[] swaps, address[] assets, (address sender, bool fromInternalBalance, address recipient, bool toInternalBalance) funds, int256[] limits, uint256 deadline) int256[] +burn(address user, uint256 amount) +burn(uint256) +burnAfterSeize(uint256 amount) uint256 +burnFrom(address to, uint256 value) bool +buyAsset(uint256 minAmount, address receiver) uint256, uint256 +buyAssetWithSig(address originator, uint256 minAmount, address receiver, uint256 deadline, bytes signature) uint256, uint256 +canPerform(bytes32 actionId, address account, address where) bool +cbrt(uint256 x) uint256 +claimMintReward() +claimMintRewardAndShare(address other, uint256 pct) +claimMintRewardAndStake(uint256 pct, uint256 term) +coins(uint256 i) address +createPair(address tokenA, address tokenB) address pair +crossLmTick(int24 tick, bool zeroForOne) +cumulativeSum() uint256 +decimals() uint8 +decreaseAllowance(address spender, uint256 subtractedValue) bool success +deposit() +description() string +DOMAIN_SEPARATOR() bytes32 +ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed) +ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed) +ERC20InvalidApprover(address approver) +ERC20InvalidReceiver(address receiver) +ERC20InvalidSender(address sender) +ERC20InvalidSpender(address spender) +ERC721IncorrectOwner(address sender, uint256 tokenId, address owner) +ERC721InsufficientApproval(address operator, uint256 tokenId) +ERC721InvalidApprover(address approver) +ERC721InvalidOperator(address operator) +ERC721InvalidOwner(address owner) +ERC721InvalidReceiver(address receiver) +ERC721InvalidSender(address sender) +ERC721NonexistentToken(uint256 tokenId) +Error(string) +exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) +exchange(int128 i, int128 j, uint256 dx, uint256 min_dy, address receiver) +exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) +exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy, bool use_eth) +exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy, bool use_eth, address receiver) uint256 +exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) +execute(bytes commands, bytes[] inputs) +execute(bytes commands, bytes[] inputs, uint256 deadline) +factory() address +fee() uint24 +feeGrowthGlobal0X128() uint256 +feeGrowthGlobal1X128() uint256 +flash(address recipient, uint256 amount0, uint256 amount1, bytes data) +geometric_mean(uint256[3] x) uint256 +get_address(uint256 idx) address +get_dy(int128 i, int128 j, uint256 amount) uint256 +get_dy_underlying(int128 i, int128 j, uint256 amount) uint256 +get_p(uint256[3] xp, uint256 D, uint256[2] A_gamma) uint256[2] +get_registry() address +get_y(uint256 ANN, uint256 gamma, uint256[3] x, uint256 D, uint256 i) uint256[2] +getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) uint256 amountIn +getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) uint256 amountOut +getAmountsIn(uint256 amountOut, address[] path) uint256[] amounts +getAmountsOut(uint256 amountIn, address[] path) uint256[] amounts +getApp(bytes32 namespace, bytes32 appId) address +getApproved(uint256 tokenId) address operator +getAssetPriceInGho(uint256 assetAmount, bool roundUp) uint256 +getAuthorizer() address +getBuyFee(uint256 grossAmount) uint256 +getGhoPriceInAsset(uint256 ghoAmount, bool roundUp) uint256 +getGrossAmountFromTotalBought(uint256 totalAmount) uint256 +getGrossAmountFromTotalSold(uint256 totalAmount) uint256 +getInternalBalance(address user, address[] tokens) uint256[] +getPair(address tokenA, address tokenB) address pair +getReserves() uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast +getRoleAdmin(bytes32 role) bytes32 +getRoleMember(bytes32 role, uint256 index) address +getRoleMemberCount(bytes32 role) uint256 +getRoundData(uint80 roundId) uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound +getSellFee(uint256 grossAmount) uint256 +grantRole(bytes32 role, address account) +hasApprovedRelayer(address user, address relayer) bool +hasPermission(address who, address where, bytes32 what, bytes how) bool +hasRole(bytes32 role, address account) bool +implementation() address +increaseAllowance(address spender, uint256 addedValue) bool success +initialize(address token0, address token1) +isApprovedForAll(address owner, address operator) bool +isSolver(address) bool +isValidSignature(bytes32 hash, bytes data) magic bytes4 +kLast() uint256 +latestRoundData() uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound +liquidity() uint128 +lmPool() address +max(uint256, uint256) uint256 +min(uint256, uint256) uint256 +MINIMUM_LIQUIDITY() uint256 +mint() +mint(address to, uint256 amount) +mint(uint256) +mint_relative(address to, uint256 frac) uint256 +name() string +newton_D(uint256 ANN, uint256 gamma, uint256[3] x_unsorted, uint256 K0_prev) uint256 +onERC721Received(address operator, address from, uint256 tokenId, bytes data) bytes4 +owner() address +ownerOf(uint256 tokenId) address +pancakeV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes data) +paused() bool +permit(address owner, ((address token, uint160 amount, uint48 expiration, uint48 nonce)[] details, address spender, uint256 sigDeadline) permitBatch, bytes signature) +permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) +price0CumulativeLast() uint256 +price1CumulativeLast() uint256 +quote(uint256 amountA, uint256 reserveA, uint256 reserveB) uint256 amountB +reduction_coefficient(uint256[3] x, uint256 fee_gamma) uint256 +removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) uint256 amountA, uint256 amountB +removeLiquidityETH(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) uint256 amountToken, uint256 amountETH +removeLiquidityETHSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) uint256 amountETH +removeLiquidityETHWithPermit(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) uint256 amountToken, uint256 amountETH +removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) uint256 amountETH +removeLiquidityWithPermit(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) uint256 amountA, uint256 amountB +renounceOwnership() +renounceRole(bytes32 role, address account) +rescueTokens(address token, address to, uint256 amount) +revokeRole(bytes32 role, address account) +safeTransferFrom(address from, address to, uint256 tokenId) +safeTransferFrom(address from, address to, uint256 tokenId, bytes data) +seize() uint256 +sellAsset(uint256 maxAmount, address receiver) uint256, uint256 +sellAssetWithSig(address originator, uint256 maxAmount, address receiver, uint256 deadline, bytes signature) uint256, uint256 +setApp(bytes32 namespace, bytes32 appId, address app) +setApprovalForAll(address operator, bool approved) +setAuthorizer(address newAuthorizer) +setRelayerApproval(address sender, address relayer, bool approved) +setSwapFeePercentage(uint256) +setSwapFreeze(bool enable) +settle((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, (bool result, address to, uint256 value, bytes data)[] interactions, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (address balanceRecipient, uint16 curFillPercent) solverData) +settle(address[] tokens, uint256[] clearingPrices, (uint256 sellTokenIndex, uint256 buyTokenIndex, address receiver, uint256 sellAmount, uint256 buyAmount, uint32 validTo, bytes32 appData, uint256 feeAmount, uint256 flags, uint256 executedAmount, bytes signature)[] trades, (address target, uint256 value, bytes callData)[][3] interactions) +settleBatch((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers)[] orders, (uint8 type, bytes signatureBytes)[] signatures, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline)[] takersPermitsInfo, (bool result, address to, uint256 value, bytes data)[] interactions, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle)[] hooks, (address balanceRecipient, uint16[] curFillPercents, bool[] takersPermitsUsage, bool transferExactAmounts) solverData) +settleInternal((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (uint256[] increasedBuyAmounts, uint16 curFillPercent) makerData) +settleInternalWithPermitsSignatures((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline) takerPermitsInfo, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (uint256[] increasedBuyAmounts, uint16 curFillPercent) makerData) +settleWithPermitsSignatures((address taker, address receiver, uint256 expiry, uint256 nonce, address executor, uint16 minFillPercent, bytes32 hooksHash, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts, uint256[] sellNFTIds, uint256[] buyNFTIds, bytes sellTokenTransfers, bytes buyTokenTransfers) order, (uint8 type, bytes signatureBytes) signature, (bytes[] permitSignatures, bytes signatureBytesPermit2, uint48[] noncesPermit2, uint48 deadline) takerPermitsInfo, (bool result, address to, uint256 value, bytes data)[] interactions, ((bool result, address to, uint256 value, bytes data)[] beforeSettle, (bool result, address to, uint256 value, bytes data)[] afterSettle) hooks, (address balanceRecipient, uint16 curFillPercent) solverData) +skim(address to) +slot0() (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked) +stake(uint256 amount, uint256 term) +supportsInterface(bytes4) bool +swap((bytes32 poolId, uint8 swapKind, address assetIn, address assetOut, uint256 amount, bytes data) singleSwap, (address sender, bool fromInternalBalance, address recipient, bool toInternalBalance) funds, uint256 limit, uint256 deadline) uint256 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes data) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes data, uint256 trackingCode) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline, bytes data) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline, bytes data, uint256 trackingCode) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 amountLimit, uint256 deadline, uint256 trackingCode) int256 amount0, int256 amount1 +swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, uint256 trackingCode) int256 amount0, int256 amount1 +swap(uint256 amount0Out, uint256 amount1Out, address to, bytes data) +swapETHForExactTokens(uint256 amountOut, address[] path, address to, uint256 deadline) uint256[] amounts +swapExactETHForTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline) uint256[] amounts +swapExactETHForTokensSupportingFeeOnTransferTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline) +swapExactTokensForETH(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) uint256[] amounts +swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) +swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) uint256[] amounts +swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) +swapTokensForExactETH(uint256 amountOut, uint256 amountInMax, address[] path, address to, uint256 deadline) uint256[] amounts +swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] path, address to, uint256 deadline) uint256[] amounts +symbol() string +sync() +tickSpacing() int24 +token() address +token0() address +token1() address +tokenURI(uint256 tokenId) string +totalShares() uint256 +totalSupply() uint256 +transfer(address to, uint256 amount) bool success +transferFrom((address from, address to, uint160 amount, address token)[] transferDetails) +transferFrom(address from, address to, uint160 amount, address token) +transferFrom(address from, address to, uint256 amount) bool success +transferFromAccounts((address account, address token, uint256 amount, bytes32 balance)[]) +transferOwnership(address newOwner) +transferTokens((address from, address receiver, address[] tokens, uint256[] amounts, uint256[] nftIds, bytes tokenTransferTypes, uint16 fillPercent) transferData) +uniswapV3Swap(uint256 amount, uint256 minReturn, uint256[] pools) uint256 returnAmount +uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes data) +updatedAt() uint256 +version() uint256 +wad_exp(int256 power) uint256 +WETH() address +withdraw(uint256) +wrapAll() diff --git a/internal/fourbyte/gen.go b/internal/fourbyte/gen.go new file mode 100644 index 00000000..d8211584 --- /dev/null +++ b/internal/fourbyte/gen.go @@ -0,0 +1,272 @@ +//go:build ignore + +package main + +import ( + "bufio" + "bytes" + "fmt" + "os" + "slices" + "strings" + "sync" + "text/template" + + "github.com/lmittmann/w3" +) + +func main() { + var ( + errFuncs, errEvents error + wg sync.WaitGroup + ) + + wg.Add(2) + go func() { + defer wg.Done() + errFuncs = genFuncs("funcs.txt", "funcs.go") + }() + go func() { + defer wg.Done() + errEvents = genEvents("events.txt", "events.go") + }() + + wg.Wait() + if errFuncs != nil { + fmt.Printf("error generating functions: %v\n", errFuncs) + } + if errEvents != nil { + fmt.Printf("error generating events: %v\n", errEvents) + } + if errFuncs != nil || errEvents != nil { + os.Exit(1) + } +} + +func genFuncs(fn, goFn string) error { + // open function definitions + f, err := os.Open(fn) + if err != nil { + return err + } + defer f.Close() + + // parse function definitions from file + var functions []function + knownIdentifiers := make(map[[4]byte]struct{}) + + scanner := bufio.NewScanner(f) + for i := 0; scanner.Scan(); i++ { + line := scanner.Text() + tokens := strings.Split(line, "\t") + if len(tokens) == 1 && strings.HasSuffix(tokens[0], ")") { + tokens = append(tokens, "") // no returns + } + if len(tokens) != 2 { + return fmt.Errorf("line %d: invalid line %q", i, line) + } + + fn, err := w3.NewFunc(tokens[0], tokens[1]) + if err != nil { + return fmt.Errorf("line %d: %v (%q)", i, err, line) + } + + if _, ok := knownIdentifiers[fn.Selector]; ok { + return fmt.Errorf("line %d: duplicate function selector %q", i, line) + } + knownIdentifiers[fn.Selector] = struct{}{} + + functions = append(functions, function{ + Selector: fn.Selector, + Signature: tokens[0], + Returns: tokens[1], + }) + } + if err := scanner.Err(); err != nil { + return fmt.Errorf("scan lines: %v", err) + } + + // make sure function definitions stay in alphabetical order + slices.SortFunc(functions, func(a, b function) int { + return strings.Compare(strings.ToLower(a.Signature), strings.ToLower(b.Signature)) + }) + f, err = os.OpenFile(fn, os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + + for _, fn := range functions { + if _, err := f.WriteString(strings.TrimSpace(fn.Signature+"\t"+fn.Returns) + "\n"); err != nil { + return err + } + } + + // generate go file + goF, err := os.Create(goFn) + if err != nil { + return err + } + defer goF.Close() + + slices.SortFunc(functions, func(a, b function) int { + return bytes.Compare(a.Selector[:], b.Selector[:]) + }) + + if err := tmplFuncs.Execute(goF, &model{Functions: functions}); err != nil { + return fmt.Errorf("execute template: %v", err) + } + + return nil +} + +func genEvents(fn, goFn string) error { + // open event definitions + f, err := os.Open(fn) + if err != nil { + return err + } + defer f.Close() + + var events []event + knownTopic0s := make(map[[32]byte]struct{}) + scanner := bufio.NewScanner(f) + for i := 0; scanner.Scan(); i++ { + line := scanner.Text() + + evt, err := w3.NewEvent(line) + if err != nil { + return fmt.Errorf("line %d: %v (%q)", i, err, line) + } + + if _, ok := knownTopic0s[evt.Topic0]; ok { + return fmt.Errorf("line %d: duplicate function selector %q", i, line) + } + knownTopic0s[evt.Topic0] = struct{}{} + + events = append(events, event{ + Topic0: evt.Topic0, + Signature: line, + }) + } + if err := scanner.Err(); err != nil { + return fmt.Errorf("scan lines: %v", err) + } + + // make sure event definitions stay in alphabetical order + slices.SortFunc(events, func(a, b event) int { + return strings.Compare(strings.ToLower(a.Signature), strings.ToLower(b.Signature)) + }) + f, err = os.OpenFile(fn, os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + + for _, evt := range events { + if _, err := f.WriteString(evt.Signature + "\n"); err != nil { + return err + } + } + + // generate go file + goF, err := os.Create(goFn) + if err != nil { + return err + } + defer goF.Close() + + slices.SortFunc(events, func(a, b event) int { + return bytes.Compare(a.Topic0[:], b.Topic0[:]) + }) + + if err := tmplEvents.Execute(goF, &model{Events: events}); err != nil { + return fmt.Errorf("execute template: %v", err) + } + + return nil + +} + +type model struct { + Functions []function + Events []event +} + +type function struct { + Selector [4]byte + Signature string + Returns string +} + +type event struct { + Topic0 [32]byte + Signature string +} + +var ( + tmplFuncs = template.Must(template.New("funcs").Parse(`// Code generated by "go generate"; DO NOT EDIT. +package fourbyte + +import "github.com/lmittmann/w3" + +var functions = map[[4]byte]*w3.Func{ + {{- range .Functions }} + {{ printf "{0x%02x, 0x%02x, 0x%02x, 0x%02x}: w3.MustNewFunc(%q, %q)" + (index .Selector 0) + (index .Selector 1) + (index .Selector 2) + (index .Selector 3) + .Signature + .Returns + }}, + {{- end }} +} +`)) + + tmplEvents = template.Must(template.New("events").Parse(`// Code generated by "go generate"; DO NOT EDIT. +package fourbyte + +import "github.com/lmittmann/w3" + +var events = map[[32]byte]*w3.Event{ + {{- range .Events }} + {{ printf "{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}: w3.MustNewEvent(%q)" + (index .Topic0 0) + (index .Topic0 1) + (index .Topic0 2) + (index .Topic0 3) + (index .Topic0 4) + (index .Topic0 5) + (index .Topic0 6) + (index .Topic0 7) + (index .Topic0 8) + (index .Topic0 9) + (index .Topic0 10) + (index .Topic0 11) + (index .Topic0 12) + (index .Topic0 13) + (index .Topic0 14) + (index .Topic0 15) + (index .Topic0 16) + (index .Topic0 17) + (index .Topic0 18) + (index .Topic0 19) + (index .Topic0 20) + (index .Topic0 21) + (index .Topic0 22) + (index .Topic0 23) + (index .Topic0 24) + (index .Topic0 25) + (index .Topic0 26) + (index .Topic0 27) + (index .Topic0 28) + (index .Topic0 29) + (index .Topic0 30) + (index .Topic0 31) + .Signature + }}, + {{- end }} +} +`)) +) diff --git a/w3vm/hooks/call_tracer.go b/w3vm/hooks/call_tracer.go new file mode 100644 index 00000000..e3d40d77 --- /dev/null +++ b/w3vm/hooks/call_tracer.go @@ -0,0 +1,487 @@ +package hooks + +import ( + "encoding/hex" + "fmt" + "io" + "math/big" + "reflect" + "strings" + "sync" + + "github.com/charmbracelet/lipgloss" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/lmittmann/w3" + "github.com/lmittmann/w3/internal/fourbyte" +) + +var ( + // styles + styleDim = lipgloss.NewStyle().Faint(true) + styleTarget = lipgloss.NewStyle().Foreground(lipgloss.Color("#EBFF71")) + styleValue = lipgloss.NewStyle().Foreground(lipgloss.Color("#71FF71")) + styleRevert = lipgloss.NewStyle().Foreground(lipgloss.Color("#FE5F86")) + stylesStaticcall = lipgloss.NewStyle().Faint(true) + stylesDelegatecall = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500")) +) + +// TargetAddress can be used to match the target (to) address in the TargetStyler +// of [CallTracerOptions]. +var TargetAddress = common.BytesToAddress([]byte("target")) + +// CallTracerOptions configures the CallTracer hook. A zero CallTracerOptions +// consists entirely of default values. +type CallTracerOptions struct { + TargetStyler func(addr common.Address) lipgloss.Style + targetAddr common.Address + + ShowStaticcall bool + + ShowOp func(op byte, pc uint64, addr common.Address) bool + OpStyler func(op byte) lipgloss.Style + + DecodeABI bool +} + +func (opts *CallTracerOptions) targetStyler(addr common.Address) lipgloss.Style { + if addr == opts.targetAddr { + addr = TargetAddress + } + + if opts.TargetStyler == nil { + return defaultTargetStyler(addr) + } + return opts.TargetStyler(addr) +} + +func (opts *CallTracerOptions) showOp(op byte, pc uint64, addr common.Address) bool { + if opts.ShowOp == nil { + return false + } + return opts.ShowOp(op, pc, addr) +} + +func (opts *CallTracerOptions) opStyler(op byte) lipgloss.Style { + if opts.OpStyler == nil { + return defaultOpStyler(op) + } + return opts.OpStyler(op) +} + +func defaultTargetStyler(addr common.Address) lipgloss.Style { + switch addr { + case TargetAddress: + return styleTarget + default: + return lipgloss.NewStyle() + } +} + +func defaultOpStyler(byte) lipgloss.Style { + return lipgloss.NewStyle() +} + +// NewCallTracer returns a new hook that writes to w and is configured with opts. +func NewCallTracer(w io.Writer, opts *CallTracerOptions) *tracing.Hooks { + if opts == nil { + opts = new(CallTracerOptions) + } + tracer := &callTracer{w: w, opts: opts} + + return &tracing.Hooks{ + OnEnter: tracer.EnterHook, + OnExit: tracer.ExitHook, + OnOpcode: tracer.OpcodeHook, + OnLog: tracer.OnLog, + } +} + +type callTracer struct { + w io.Writer + opts *CallTracerOptions + once sync.Once + + callStack []call + + // isInStaticcall is the number of nested staticcalls on the callStack. + // It is only incremented if opts.ShowStatic is true. + isInStaticcall int +} + +func (c *callTracer) EnterHook(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + c.once.Do(func() { + c.opts.targetAddr = to + }) + + var ( + fn *w3.Func + isPrecompile bool + ) + if c.opts.DecodeABI && len(input) >= 4 { + sig := ([4]byte)(input[:4]) + fn, isPrecompile = fourbyte.Function(sig, to) + } + + callType := vm.OpCode(typ) + defer func() { c.callStack = append(c.callStack, call{callType, to, fn}) }() + if !c.opts.ShowStaticcall && callType == vm.STATICCALL { + c.isInStaticcall++ + } + if c.isInStaticcall > 0 { + return + } + + fmt.Fprintf(c.w, "%s%s %s%s%s\n", renderIdent(c.callStack, c.opts.targetStyler, 1), renderAddr(to, c.opts.targetStyler), renderCallType(typ), renderValue(c.opts.DecodeABI, value), renderInput(fn, isPrecompile, input, c.opts.targetStyler)) +} + +func (c *callTracer) ExitHook(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + call := c.callStack[len(c.callStack)-1] + defer func() { c.callStack = c.callStack[:depth] }() + + if !c.opts.ShowStaticcall && call.Type == vm.STATICCALL { + defer func() { c.isInStaticcall-- }() + } + if c.isInStaticcall > 0 { + return + } + + if reverted { + reason, unpackErr := abi.UnpackRevert(output) + if unpackErr != nil { + reason = hex.EncodeToString(output) + } + fmt.Fprintf(c.w, "%s%s\n", renderIdent(c.callStack, c.opts.targetStyler, -1), styleRevert.Render(fmt.Sprintf("[%d]", gasUsed), err.Error()+":", reason)) + } else { + fmt.Fprintf(c.w, "%s[%d] %s\n", renderIdent(c.callStack, c.opts.targetStyler, -1), gasUsed, renderOutput(call.Func, output, c.opts.targetStyler)) + } +} + +func (c *callTracer) OpcodeHook(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if c.isInStaticcall > 0 || + !c.opts.showOp(op, pc, scope.Address()) { + return + } + fmt.Fprintln(c.w, renderIdent(c.callStack, c.opts.targetStyler, 0)+renderOp(op, c.opts.opStyler, pc, scope)) +} + +func (c *callTracer) OnLog(log *types.Log) { + if c.isInStaticcall > 0 { + return + } +} + +func renderIdent(callStack []call, styler func(addr common.Address) lipgloss.Style, kind int) (ident string) { + for i, call := range callStack { + style := styler(call.Target) + + s := "│ " + if isLast := i == len(callStack)-1; isLast { + switch kind { + case 1: + s = "├╴" + case -1: + s = "└╴" + } + } + ident += style.Faint(true).Render(s) + } + return ident +} + +func renderAddr(addr common.Address, styler func(addr common.Address) lipgloss.Style) string { + return styler(addr).Render(addr.Hex()) +} + +func renderCallType(typ byte) string { + switch vm.OpCode(typ) { + case vm.CALL: + return "" + case vm.STATICCALL: + return stylesStaticcall.Render("static") + " " + case vm.DELEGATECALL: + return stylesDelegatecall.Render("delegate") + " " + case vm.CREATE: + return "create " + case vm.CREATE2: + return "create2 " + default: + panic(fmt.Sprintf("unknown call type %92x", typ)) + } +} + +func renderValue(decodeABI bool, val *big.Int) string { + if val == nil || val.Sign() == 0 { + return "" + } + if !decodeABI { + return styleValue.Render(val.String(), "ETH") + " " + } + return styleValue.Render(w3.FromWei(val, 18), "ETH") + " " +} + +func renderInput(fn *w3.Func, isPrecompile bool, input []byte, styler func(addr common.Address) lipgloss.Style) string { + if fn != nil && len(input) >= 4 { + s, err := renderAbiInput(fn, isPrecompile, input, styler) + if err == nil { + return s + } + } + return renderRawInput(input, styler) +} + +func renderOutput(fn *w3.Func, output []byte, styler func(addr common.Address) lipgloss.Style) string { + if fn != nil && len(output) >= 4 { + s, err := renderAbiOutput(fn, output, styler) + if err == nil { + return s + } + } + return renderRawOutput(output, styler) +} + +func renderRawInput(input []byte, styler func(addr common.Address) lipgloss.Style) (s string) { + s = "0x" + if len(input)%32 == 4 { + s += hex.EncodeToString(input[:4]) + for i := 4; i < len(input); i += 32 { + s += renderWord(input[i:i+32], styler) + } + } else { + s += hex.EncodeToString(input) + } + return +} + +func renderRawOutput(output []byte, styler func(addr common.Address) lipgloss.Style) (s string) { + s = "0x" + if len(output)%32 == 0 { + for i := 0; i < len(output); i += 32 { + s += renderWord(output[i:i+32], styler) + } + } else { + s += hex.EncodeToString(output) + } + return +} + +func renderWord(word []byte, _ func(addr common.Address) lipgloss.Style) string { + s := hex.EncodeToString(word) + nonZeroWord := strings.TrimLeft(s, "0") + if len(nonZeroWord) < len(s) { + s = styleDim.Render(strings.Repeat("0", len(s)-len(nonZeroWord))) + nonZeroWord + } + return s +} + +func renderAbiInput(fn *w3.Func, isPrecompile bool, input []byte, styler func(addr common.Address) lipgloss.Style) (string, error) { + if !isPrecompile { + input = input[4:] + } + + args, err := fn.Args.Unpack(input) + if err != nil { + return "", err + } + + funcName := strings.Split(fn.Signature, "(")[0] + return funcName + "(" + renderAbiArgs(fn.Args, args, styler) + ")", nil +} + +func renderAbiOutput(fn *w3.Func, output []byte, styler func(addr common.Address) lipgloss.Style) (string, error) { + returns, err := fn.Returns.Unpack(output) + if err != nil { + return "", err + } + + return renderAbiArgs(fn.Returns, returns, styler), nil +} + +func renderAbiArgs(args abi.Arguments, vals []any, styler func(addr common.Address) lipgloss.Style) (s string) { + for i, val := range vals { + arg := args[i] + s += renderAbiTyp(&arg.Type, arg.Name, val, styler) + if i < len(vals)-1 { + s += styleDim.Render(",") + " " + } + } + return +} + +func renderAbiTyp(typ *abi.Type, name string, val any, styler func(addr common.Address) lipgloss.Style) (s string) { + if name != "" { + s += styleDim.Render(name+":") + " " + } + + switch val := val.(type) { + case []byte: + s += "0x" + hex.EncodeToString(val) + case [32]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [31]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [30]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [29]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [28]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [27]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [26]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [25]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [24]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [23]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [22]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [21]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [20]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [19]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [18]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [17]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [16]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [15]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [14]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [13]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [12]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [11]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [10]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [9]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [8]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [7]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [6]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [5]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [4]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [3]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [2]byte: + s += "0x" + hex.EncodeToString(val[:]) + case [1]byte: + s += "0x" + hex.EncodeToString(val[:]) + case common.Address: + style := styler(val) + s += style.Render(val.Hex()) + case common.Hash: + s += val.Hex() + case any: // tuple, array, or slice + switch refVal := reflect.ValueOf(val); refVal.Kind() { + case reflect.Slice: + s += "[" + for i := range refVal.Len() { + s += renderAbiTyp(typ.Elem, "", refVal.Index(i).Interface(), styler) + + if i < refVal.Len()-1 { + s += styleDim.Render(",") + " " + } + } + s += "]" + case reflect.Array: + s += "[" + for i := range refVal.Len() { + s += renderAbiTyp(typ.Elem, "", refVal.Index(i).Interface(), styler) + + if i < refVal.Len()-1 { + s += styleDim.Render(",") + " " + } + } + s += "]" + case reflect.Struct: + s += "(" + for i := range refVal.NumField() { + s += renderAbiTyp(typ.TupleElems[i], typ.TupleRawNames[i], refVal.Field(i).Interface(), styler) + + if i < refVal.NumField()-1 { + s += styleDim.Render(",") + " " + } + } + s += ")" + default: + s += fmt.Sprintf("%v", val) + } + default: + s += fmt.Sprintf("%v", val) + } + return s +} + +func renderOp(op byte, style func(byte) lipgloss.Style, pc uint64, scope tracing.OpContext) string { + const maxStackDepth = 7 + sb := new(strings.Builder) + sb.WriteString(styleDim.Render(fmt.Sprintf("0x%04x ", pc))) + sb.WriteString(style(op).Render(fmt.Sprintf("%-12s ", vm.OpCode(op)))) + + stack := scope.StackData() + for i, j := len(stack)-1, 0; i >= 0 && i >= len(stack)-maxStackDepth; i, j = i-1, j+1 { + notLast := i > 0 && i > len(stack)-maxStackDepth + if isAccessed := opAccessesStackElem(op, j); isAccessed { + sb.WriteString(stack[i].Hex()) + } else { + sb.WriteString(styleDim.Render(stack[i].Hex())) + } + if notLast { + sb.WriteString(" ") + } + } + + if len(stack) > maxStackDepth { + sb.WriteString(styleDim.Render(fmt.Sprintf(" …%d", len(stack)-maxStackDepth))) + } + + return sb.String() +} + +// call stores state of the current call in execution. +type call struct { + Type vm.OpCode + Target common.Address + Func *w3.Func +} + +// opAccessesStackElem returns true, if the given opcode accesses the stack at +// index i, otherwise false. +func opAccessesStackElem(op byte, i int) bool { + switch { + case vm.SWAP1 <= op && op <= vm.SWAP16: + return i == 0 || i == int(op)-int(vm.SWAP1)+1 + case vm.DUP1 <= op && op <= vm.DUP16: + return i == int(op)-int(vm.DUP1) + default: + return i < pops[op] + } +} + +var pops = [256]int{ + vm.STOP: 0, vm.ADD: 2, vm.MUL: 2, vm.SUB: 2, vm.DIV: 2, vm.SDIV: 2, vm.MOD: 2, vm.SMOD: 2, vm.ADDMOD: 3, vm.MULMOD: 3, vm.EXP: 2, vm.SIGNEXTEND: 2, + vm.LT: 2, vm.GT: 2, vm.SLT: 2, vm.SGT: 2, vm.EQ: 2, vm.ISZERO: 1, vm.AND: 2, vm.OR: 2, vm.XOR: 2, vm.NOT: 1, vm.BYTE: 2, vm.SHL: 2, vm.SHR: 2, vm.SAR: 2, + vm.KECCAK256: 2, + vm.BALANCE: 1, vm.CALLDATALOAD: 1, vm.CALLDATACOPY: 3, vm.CODECOPY: 3, vm.EXTCODESIZE: 1, vm.EXTCODECOPY: 4, vm.RETURNDATACOPY: 3, vm.EXTCODEHASH: 1, + vm.BLOCKHASH: 1, vm.BLOBHASH: 1, + vm.POP: 1, vm.MLOAD: 1, vm.MSTORE: 2, vm.MSTORE8: 2, vm.SLOAD: 1, vm.SSTORE: 2, vm.JUMP: 1, vm.JUMPI: 2, vm.TLOAD: 1, vm.TSTORE: 2, vm.MCOPY: 3, + vm.LOG0: 2, vm.LOG1: 3, vm.LOG2: 4, vm.LOG3: 5, vm.LOG4: 6, + vm.CREATE: 3, vm.CALL: 7, vm.CALLCODE: 7, vm.RETURN: 2, vm.DELEGATECALL: 6, vm.CREATE2: 4, vm.STATICCALL: 6, vm.REVERT: 2, vm.SELFDESTRUCT: 1, +} From 617cb2a1233b9c93aa512d8cf0e680722e29f15e Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:59:14 +0200 Subject: [PATCH 4/9] docs: Improved Examples (#194) * w3vm: restructured and added examples * moved rpc examples + created new examples * added callFunc examples * dropped `examples/` directory * workflows: fix * update doc * fmt * fmt * added tracing examples * cleanup * . * . * added example section * test * fix * test * cleanup * fix * drop redirects * link fixes * added releases * added sponsor notice * small fix --------- Co-authored-by: lmittmann --- .github/workflows/go.yml | 4 +- README.md | 18 +- client_test.go | 213 -------------- docs/pages/_meta.js | 8 +- docs/pages/examples.mdx | 0 docs/pages/examples/_meta.js | 7 + docs/pages/examples/index.mdx | 34 +++ docs/pages/index.mdx | 10 +- docs/pages/style.css | 1 + docs/public/_redirects | 1 - docs/public/ef-logo-dark.svg | 1 + docs/public/ef-logo.svg | 1 + event_test.go | 28 -- example_test.go | 496 +++++++++++++++++++++++++++++++++ examples/README.md | 10 - examples/go.mod | 37 --- examples/go.sum | 145 ---------- examples/scan_blocks/main.go | 74 ----- examples/token_balance/main.go | 72 ----- examples/uniswap_quote/main.go | 111 -------- func_test.go | 101 ------- w3vm/example_test.go | 351 +++++++++++++++++++++++ w3vm/vm_test.go | 146 ---------- 23 files changed, 920 insertions(+), 949 deletions(-) create mode 100644 docs/pages/examples.mdx create mode 100644 docs/pages/examples/_meta.js create mode 100644 docs/pages/examples/index.mdx create mode 100644 docs/public/ef-logo-dark.svg create mode 100644 docs/public/ef-logo.svg create mode 100644 example_test.go delete mode 100644 examples/README.md delete mode 100644 examples/go.mod delete mode 100644 examples/go.sum delete mode 100644 examples/scan_blocks/main.go delete mode 100644 examples/token_balance/main.go delete mode 100644 examples/uniswap_quote/main.go create mode 100644 w3vm/example_test.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 92398cff..c6eba1fb 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -27,9 +27,7 @@ jobs: - name: staticcheck run: staticcheck ./... - name: go mod tidy - run: | - go mod tidy -diff - cd examples/ && go mod tidy -diff + run: go mod tidy -diff test: name: Test diff --git a/README.md b/README.md index 7daff0d8..2cf85562 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ go get github.com/lmittmann/w3 [`w3.Client`](https://pkg.go.dev/github.com/lmittmann/w3#Client) is a batch request focused RPC client that can be used to connect to an Ethereum node via HTTP, WebSocket, or IPC. Its modular API allows to create custom RPC method integrations that can be used alongside the common methods implemented by this package. -**Example:** Batch Request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client)) +**Example:** Batch Request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchEOAState)) ```go // 1. Connect to an RPC endpoint @@ -59,10 +59,10 @@ if err := client.Call( If one or more calls in a batch request fail, `Client.Call` returns an error of type [`w3.CallErrors`](https://pkg.go.dev/github.com/lmittmann/w3#CallErrors). -**Example:** Check which RPC calls failed in a batch request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-CallErrors)) +**Example:** Check which RPC calls failed in a batch request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchHandleError)) ```go -var errs w3.CallErrors -if err := client.Call(rpcCalls...); errors.As(err, &errs) { +var batchErr w3.CallErrors +if err := client.Call(calls...); errors.As(err, &batchErr) { // handle call errors } else if err != nil { // handle other errors @@ -77,7 +77,7 @@ if err := client.Call(rpcCalls...); errors.As(err, &errs) { [`w3vm.VM`](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#VM) is a high-level EVM environment with a simple but powerful API to simulate EVM execution, test Smart Contracts, or trace transactions. It supports Mainnet state forking via RPC and state caching for faster testing. -**Example:** Simulate an Uniswap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) +**Example:** Simulate an Uniswap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-UniswapV3Swap)) ```go // 1. Create a VM that forks the Mainnet state from the latest block, @@ -273,3 +273,11 @@ func (f *getTransactionBySenderAndNonceFactory) HandleResponse(elem rpc.BatchEle return nil } ``` + +## Sponsors + + + + + ef logo + diff --git a/client_test.go b/client_test.go index abb0e0d9..94e4729a 100644 --- a/client_test.go +++ b/client_test.go @@ -5,18 +5,14 @@ import ( "context" "errors" "flag" - "fmt" "math/big" "strconv" "testing" - "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/google/go-cmp/cmp" "github.com/lmittmann/w3" @@ -24,7 +20,6 @@ import ( "github.com/lmittmann/w3/module/eth" "github.com/lmittmann/w3/rpctest" "github.com/lmittmann/w3/w3types" - "golang.org/x/time/rate" ) var ( @@ -36,189 +31,6 @@ var ( `< [{"jsonrpc":"2.0","id":1,"result":"0x1"},{"jsonrpc":"2.0","id":2,"result":"0x1"}]` ) -func ExampleClient() { - addr := w3.A("0x0000000000000000000000000000000000000000") - - // 1. Connect to an RPC endpoint - client, err := w3.Dial("https://rpc.ankr.com/eth") - if err != nil { - // handle error - } - defer client.Close() - - // 2. Make a batch request - var ( - balance *big.Int - nonce uint64 - ) - if err := client.Call( - eth.Balance(addr, nil).Returns(&balance), - eth.Nonce(addr, nil).Returns(&nonce), - ); err != nil { - // handle error - } - - fmt.Printf("balance: %s\nnonce: %d\n", w3.FromWei(balance, 18), nonce) -} - -func ExampleClient_Call_balanceOf() { - // Connect to RPC endpoint (or panic on error) and - // close the connection when you are done. - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - var ( - addr = w3.A("0x000000000000000000000000000000000000dEaD") - weth9 = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - - // Declare a Smart Contract function using Solidity syntax, - // no "abigen" and ABI JSON file needed. - balanceOf = w3.MustNewFunc("balanceOf(address)", "uint256") - - // Declare variables for the RPC responses. - ethBalance *big.Int - weth9Balance *big.Int - ) - - // Do batch request (both RPC requests are send in the same - // HTTP request). - if err := client.Call( - eth.Balance(addr, nil).Returns(ðBalance), - eth.CallFunc(weth9, balanceOf, addr).Returns(&weth9Balance), - ); err != nil { - fmt.Printf("Request failed: %v\n", err) - return - } - - fmt.Printf("Combined balance: %v wei", - new(big.Int).Add(ethBalance, weth9Balance), - ) -} - -func ExampleClient_Call_nonceAndBalance() { - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - var ( - addr = w3.A("0x000000000000000000000000000000000000c0Fe") - - nonce uint64 - balance *big.Int - ) - - if err := client.Call( - eth.Nonce(addr, nil).Returns(&nonce), - eth.Balance(addr, nil).Returns(&balance), - ); err != nil { - fmt.Printf("Request failed: %v\n", err) - return - } - - fmt.Printf("%s: Nonce: %d, Balance: ♦%s\n", addr, nonce, w3.FromWei(balance, 18)) -} - -func ExampleClient_Call_sendERC20transferTx() { - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - var ( - weth9 = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - receiver = w3.A("0x000000000000000000000000000000000000c0Fe") - eoaPrv, _ = crypto.GenerateKey() - ) - - funcTransfer := w3.MustNewFunc("transfer(address receiver, uint256 amount)", "bool") - input, err := funcTransfer.EncodeArgs(receiver, w3.I("1 ether")) - if err != nil { - fmt.Printf("Failed to encode args: %v\n", err) - return - } - - signer := types.LatestSigner(params.MainnetChainConfig) - var txHash common.Hash - if err := client.Call( - eth.SendTx(types.MustSignNewTx(eoaPrv, signer, &types.DynamicFeeTx{ - Nonce: 0, - To: &weth9, - Data: input, - GasTipCap: w3.I("1 gwei"), - GasFeeCap: w3.I("100 gwei"), - Gas: 100_000, - })).Returns(&txHash), - ); err != nil { - fmt.Printf("Failed to send tx: %v\n", err) - return - } - - fmt.Printf("Sent tx: %s\n", txHash) -} - -func ExampleCallErrors() { - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - funcSymbol := w3.MustNewFunc("symbol()", "string") - - // list of addresses that might be an ERC20 token - potentialTokens := []common.Address{ - w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), - w3.A("0x00000000219ab540356cBB839Cbe05303d7705Fa"), - } - - // build symbol()-call for each potential ERC20 token - tokenSymbols := make([]string, len(potentialTokens)) - rpcCalls := make([]w3types.RPCCaller, len(potentialTokens)) - for i, addr := range potentialTokens { - rpcCalls[i] = eth.CallFunc(addr, funcSymbol).Returns(&tokenSymbols[i]) - } - - // execute batch request - var errs w3.CallErrors - if err := client.Call(rpcCalls...); errors.As(err, &errs) { - // handle call errors - } else if err != nil { - // handle other errors - fmt.Printf("Request failed: %v\n", err) - return - } - - for i, addr := range potentialTokens { - var symbol string - if errs == nil || errs[i] == nil { - symbol = tokenSymbols[i] - } else { - symbol = fmt.Sprintf("unknown symbol: %v", errs[i].Error()) - } - fmt.Printf("%s: %s\n", addr, symbol) - } - - // Output: - // 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2: WETH - // 0x00000000219ab540356cBB839Cbe05303d7705Fa: unknown symbol: execution reverted -} - -func ExampleClient_Subscribe() { - client := w3.MustDial("wss://mainnet.gateway.tenderly.co") - defer client.Close() - - txCh := make(chan *types.Transaction) - sub, err := client.Subscribe(eth.PendingTransactions(txCh)) - if err != nil { - fmt.Printf("Failed to subscribe: %v\n", err) - return - } - - for { - select { - case tx := <-txCh: - fmt.Printf("New pending tx: %s\n", tx.Hash()) - case err := <-sub.Err(): - fmt.Printf("Subscription error: %v\n", err) - return - } - } -} - func TestClientCall(t *testing.T) { tests := []struct { Buf *bytes.Buffer @@ -480,28 +292,3 @@ func BenchmarkCall_Block100(b *testing.B) { } }) } - -func ExampleWithRateLimiter() { - // Limit the client to 30 requests per second and allow bursts of up to - // 100 requests. - client := w3.MustDial("https://rpc.ankr.com/eth", - w3.WithRateLimiter(rate.NewLimiter(rate.Every(time.Second/30), 100), nil), - ) - defer client.Close() -} - -func ExampleWithRateLimiter_costFunc() { - // Limit the client to 30 calls per second and allow bursts of up to - // 100 calls using a cost function. Batch requests have an additional charge. - client := w3.MustDial("https://rpc.ankr.com/eth", - w3.WithRateLimiter(rate.NewLimiter(rate.Every(time.Second/30), 100), - func(methods []string) (cost int) { - cost = len(methods) // charge 1 CU per call - if len(methods) > 1 { - cost += 1 // charge 1 CU extra for the batch itself - } - return cost - }, - )) - defer client.Close() -} diff --git a/docs/pages/_meta.js b/docs/pages/_meta.js index 025426dd..e65285a0 100644 --- a/docs/pages/_meta.js +++ b/docs/pages/_meta.js @@ -7,7 +7,7 @@ export default { '404': { title: '404', display: 'hidden', - 'theme': { + theme: { breadcrumb: false, toc: false, layout: 'full', @@ -69,7 +69,11 @@ export default { examples: { title: 'Examples', type: 'page', - href: 'https://github.com/lmittmann/w3/tree/main/examples', + }, + releases: { + title: 'Releases', + type: 'page', + href: 'https://github.com/lmittmann/w3/releases', newWindow: true }, godoc: { diff --git a/docs/pages/examples.mdx b/docs/pages/examples.mdx new file mode 100644 index 00000000..e69de29b diff --git a/docs/pages/examples/_meta.js b/docs/pages/examples/_meta.js new file mode 100644 index 00000000..d7bd5dc7 --- /dev/null +++ b/docs/pages/examples/_meta.js @@ -0,0 +1,7 @@ +export default { + index: { + title: 'Examples', + display: 'hidden', + theme: { breadcrumb: false, toc: true, pagination: false }, + }, +} diff --git a/docs/pages/examples/index.mdx b/docs/pages/examples/index.mdx new file mode 100644 index 00000000..29fe4852 --- /dev/null +++ b/docs/pages/examples/index.mdx @@ -0,0 +1,34 @@ +# Examples + +## `w3.Client` Examples + +* **Batch Fetch** 1000 blocks ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchBlocks)) +* **Batch Call** the name, symbol, decimals, and balanceOf functions of the Wrapped Ether in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchCallFunc)) +* **Batch Call** the Uniswap V3 Quoter for quotes on swapping 100 WETH for DAI in pools of all fee tiers in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchCallFuncUniswapQuoter)) +* **Batch Fetch** the nonce and balance of an EOA in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchEOAState)) +* **Batch Fetch** a transaction and its receipt in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchTxDetails)) +* **Call** the token balance of an address ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-CallFunc)) +* **Call** the token balance of an address, with state override ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-CallFuncWithStateOverride)) +* **Handle errors** of individual calls in a batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchHandleError)) +* **Rate Limit** the number of requests to 300 compute units (CUs) per second, with bursts of up to 300 CUs. An individual CU can be charged per RPC method call ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-RateLimitByComputeUnits)) +* **Rate Limit** the number of requests to 10 per second, with bursts of up to 20 requests ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-RateLimitByRequest)) +* **Send Ether** transfer ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-SendETHTransfer)) +* **Send ERC20 token** transfer (Wrapped Ether) ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-SendTokenTransfer)) +* **Subscribe** to pending transactions ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-SubscribeToPendingTransactions)) + +**[See all examples ↗](https://pkg.go.dev/github.com/lmittmann/w3#pkg-examples)** + + +## `w3vm.VM` Examples + +* **Ether transfer** ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-SimpleTransfer)) +* **ERC20 token transfer** with faked token balance (Wrapped Ether) ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-FakeTokenBalance)) +* **Uniswap V3 swap** ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-UniswapV3Swap)) + +* **Call ERC20 balanceOf** with raw a `w3types.Message` using the `Message.{Func,Args}` helper ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-Call)) +* **Call ERC20 balanceOf**, using the `VM.CallFunc` helper ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-CallFunc)) +* **Prank** a sender ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-PrankZeroAddress)) +* **Trace** the execution to obtain the access list ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceAccessList)) +* **Trace** the execution of all op's in a block ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceBlock)) + +**[See all examples ↗](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#pkg-examples)** diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx index b3d55ebc..78e51067 100644 --- a/docs/pages/index.mdx +++ b/docs/pages/index.mdx @@ -19,7 +19,7 @@ description: 'w3: Enhanced Ethereum Integration for Go' -Hello +W3 Gopher `w3` is your toolbelt for integrating with Ethereum in Go. Closely linked to `go‑ethereum`, it provides an ergonomic wrapper for working with **RPC**, **ABI's**, and the **EVM**. @@ -35,3 +35,11 @@ go get github.com/lmittmann/w3 * Use `w3vm.VM` to simulate EVM execution with optional tracing and Mainnet state forking, or test Smart Contracts. [learn more ➔](/vm-overview) * Use `w3.Func` and `w3.Event` to create ABI bindings from Solidity function and event signatures. [learn more ➔](/helper-abi) * Use `w3.A`, `w3.H`, and many other utility functions to parse addresses, hashes, and other common types from strings. [learn more ➔](/helper-utils) + + +## Sponsors + +
+ EF Logo + +
diff --git a/docs/pages/style.css b/docs/pages/style.css index 3c362910..b939958f 100644 --- a/docs/pages/style.css +++ b/docs/pages/style.css @@ -36,6 +36,7 @@ tr._border-gray-300 { /* Customize header */ .nextra-nav-container nav a[target="_blank"]:nth-child(2):after, .nextra-nav-container nav a[target="_blank"]:nth-child(3):after, +.nextra-nav-container nav a[target="_blank"]:nth-child(4):after, aside.nextra-sidebar-container li a[target="_blank"]:after { content: url('data:image/svg+xml,'); @apply pl-2; diff --git a/docs/public/_redirects b/docs/public/_redirects index 4ccfb0c3..e69de29b 100644 --- a/docs/public/_redirects +++ b/docs/public/_redirects @@ -1 +0,0 @@ -/examples https://github.com/lmittmann/w3/tree/main/examples diff --git a/docs/public/ef-logo-dark.svg b/docs/public/ef-logo-dark.svg new file mode 100644 index 00000000..9b6c5298 --- /dev/null +++ b/docs/public/ef-logo-dark.svg @@ -0,0 +1 @@ + diff --git a/docs/public/ef-logo.svg b/docs/public/ef-logo.svg new file mode 100644 index 00000000..ebffdce7 --- /dev/null +++ b/docs/public/ef-logo.svg @@ -0,0 +1 @@ +f1f5f9 diff --git a/event_test.go b/event_test.go index b8c037aa..62113302 100644 --- a/event_test.go +++ b/event_test.go @@ -1,7 +1,6 @@ package w3_test import ( - "fmt" "math/big" "strconv" "testing" @@ -13,33 +12,6 @@ import ( "github.com/lmittmann/w3" ) -func ExampleEvent_DecodeArgs() { - var ( - eventTransfer = w3.MustNewEvent("Transfer(address indexed from, address indexed to, uint256 value)") - log = &types.Log{ - Address: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), - Topics: []common.Hash{ - w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), - w3.H("0x000000000000000000000000000000000000000000000000000000000000c0fe"), - w3.H("0x000000000000000000000000000000000000000000000000000000000000dead"), - }, - Data: w3.B("0x0000000000000000000000000000000000000000000000001111d67bb1bb0000"), - } - - from common.Address - to common.Address - value big.Int - ) - - if err := eventTransfer.DecodeArgs(log, &from, &to, &value); err != nil { - fmt.Printf("Failed to decode event log: %v\n", err) - return - } - fmt.Printf("Transferred %s WETH9 from %s to %s", w3.FromWei(&value, 18), from, to) - // Output: - // Transferred 1.23 WETH9 from 0x000000000000000000000000000000000000c0Fe to 0x000000000000000000000000000000000000dEaD -} - func TestNewEvent(t *testing.T) { tests := []struct { Signature string diff --git a/example_test.go b/example_test.go new file mode 100644 index 00000000..5ddd4d71 --- /dev/null +++ b/example_test.go @@ -0,0 +1,496 @@ +package w3_test + +import ( + "crypto/ecdsa" + "errors" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/lmittmann/w3" + "github.com/lmittmann/w3/module/eth" + "github.com/lmittmann/w3/w3types" + "github.com/lmittmann/w3/w3vm" + "golang.org/x/time/rate" +) + +var ( + funcName = w3.MustNewFunc("name()", "string") + funcSymbol = w3.MustNewFunc("symbol()", "string") + funcDecimals = w3.MustNewFunc("decimals()", "uint8") + funcBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256") + + addrA = common.Address{0x0a} + addrB = common.Address{0x0b} + + prvA *ecdsa.PrivateKey // dummy private key for addrA + + addrWETH = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + addrDAI = w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F") + + client = w3.MustDial("https://rpc.ankr.com/eth") +) + +// Call the name, symbol, decimals, and balanceOf functions of the Wrapped Ether +// in a single batch. +func ExampleClient_batchCallFunc() { + blockNumber := big.NewInt(20_000_000) + + var ( + name, symbol string + decimals uint8 + balance big.Int + ) + if err := client.Call( + eth.CallFunc(addrWETH, funcName).Returns(&name), + eth.CallFunc(addrWETH, funcSymbol).Returns(&symbol), + eth.CallFunc(addrWETH, funcDecimals).Returns(&decimals), + eth.CallFunc(addrWETH, funcBalanceOf, addrWETH).AtBlock(blockNumber).Returns(&balance), + ); err != nil { + // ... + } + + fmt.Printf("%s's own balance: %s %s\n", name, w3.FromWei(&balance, decimals), symbol) + // Output: + // Wrapped Ether's own balance: 748.980125465356473638 WETH +} + +// Call the Uniswap V3 Quoter for quotes on swapping 100 WETH for DAI in pools +// of all fee tiers in a single batch. +func ExampleClient_batchCallFuncUniswapQuoter() { + blockNumber := big.NewInt(20_000_000) + + var ( + addrUniswapV3Quoter = w3.A("0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6") + addrTokenIn = addrWETH + addrTokenOut = addrDAI + + funcQuote = w3.MustNewFunc(`quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96clear + )`, "uint256 amountOut") + ) + + var ( + amountIn = w3.I("100 ether") + amountOut100 *big.Int + amountOut500 *big.Int + amountOut3000 *big.Int + amountOut10000 *big.Int + ) + if err := client.Call( + eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(100), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut100), + eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(500), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut500), + eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(3000), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut3000), + eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(10000), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut10000), + ); err != nil { + // ... + } + fmt.Println("Swap 100 WETH for DAI:") + fmt.Printf("Pool with 0.01%% fee: %s DAI\n", w3.FromWei(amountOut100, 18)) + fmt.Printf("Pool with 0.05%% fee: %s DAI\n", w3.FromWei(amountOut500, 18)) + fmt.Printf("Pool with 0.3%% fee: %s DAI\n", w3.FromWei(amountOut3000, 18)) + fmt.Printf("Pool with 1%% fee: %s DAI\n", w3.FromWei(amountOut10000, 18)) + // Output: + // Swap 100 WETH for DAI: + // Pool with 0.01% fee: 0.840975419471618588 DAI + // Pool with 0.05% fee: 371877.453117609415215338 DAI + // Pool with 0.3% fee: 378532.856217317782434539 DAI + // Pool with 1% fee: 3447.634026125332130689 DAI +} + +// Fetch the nonce and balance of an EOA in a single batch. +func ExampleClient_batchEOAState() { + var ( + nonce uint64 + balance *big.Int + ) + if err := client.Call( + eth.Nonce(addrA, nil).Returns(&nonce), + eth.Balance(addrA, nil).Returns(&balance), + ); err != nil { + // ... + } + + fmt.Printf("Nonce: %d\nBalance: %d\n", nonce, balance) +} + +// Fetch a transaction and its receipt in a single batch. +func ExampleClient_batchTxDetails() { + txHash := w3.H("0xc31d7e7e85cab1d38ce1b8ac17e821ccd47dbde00f9d57f2bd8613bff9428396") + + var ( + tx *types.Transaction + receipt *types.Receipt + ) + if err := client.Call( + eth.Tx(txHash).Returns(&tx), + eth.TxReceipt(txHash).Returns(&receipt), + ); err != nil { + // ... + } + + fmt.Printf("Tx: %#v\nReceipt: %#v\n", tx, receipt) +} + +// Fetch 1000 blocks in batches. +func ExampleClient_batchBlocks() { + const ( + startBlock = 20_000_000 + nBlocks = 1000 + batchSize = 100 + ) + + blocks := make([]*types.Block, nBlocks) + calls := make([]w3types.RPCCaller, batchSize) + for i := 0; i < nBlocks; i += batchSize { + for j := 0; j < batchSize; j++ { + blockNumber := new(big.Int).SetUint64(uint64(startBlock + i + j)) + calls[j] = eth.BlockByNumber(blockNumber).Returns(&blocks[i+j]) + } + if err := client.Call(calls...); err != nil { + // ... + } + fmt.Printf("Fetched %d blocks\n", i+batchSize) + } +} + +// Handle errors of individual calls in a batch. +func ExampleClient_batchHandleError() { + tokens := []common.Address{addrWETH, addrA, addrB} + symbols := make([]string, len(tokens)) + + // build rpc calls + calls := make([]w3types.RPCCaller, len(tokens)) + for i, token := range tokens { + calls[i] = eth.CallFunc(token, funcSymbol).Returns(&symbols[i]) + } + + var batchErr w3.CallErrors + if err := client.Call(calls...); errors.As(err, &batchErr) { + } else if err != nil { + // all calls failed + } + + for i, symbol := range symbols { + if len(batchErr) > 0 && batchErr[i] != nil { + symbol = "call failed" + } + fmt.Printf("%s: %s\n", tokens[i], symbol) + } + // Output: + // 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2: WETH + // 0x0a00000000000000000000000000000000000000: call failed + // 0x0B00000000000000000000000000000000000000: call failed +} + +// Fetch the token balance of an address. +func ExampleClient_callFunc() { + var balance *big.Int + if err := client.Call( + eth.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&balance), + ); err != nil { + // ... + } + + fmt.Printf("Balance: %s WETH\n", w3.FromWei(balance, 18)) + // Output: + // Balance: 0 WETH +} + +// Fetch the token balance of an address, with state override. +func ExampleClient_callFuncWithStateOverride() { + var balance *big.Int + if err := client.Call( + eth.CallFunc(addrWETH, funcBalanceOf, addrA).Overrides(w3types.State{ + addrWETH: {Storage: w3types.Storage{ + w3vm.WETHBalanceSlot(addrA): common.BigToHash(w3.I("100 ether")), + }}, + }).Returns(&balance), + ); err != nil { + // ... + } + + fmt.Printf("Balance: %s WETH\n", w3.FromWei(balance, 18)) + // Output: + // Balance: 100 WETH +} + +// Send Ether transfer. +func ExampleClient_sendETHTransfer() { + var ( + nonce uint64 + gasPrice *big.Int + ) + if err := client.Call( + eth.Nonce(addrA, nil).Returns(&nonce), + eth.GasPrice().Returns(&gasPrice), + ); err != nil { + // ... + } + + signer := types.LatestSigner(params.MainnetChainConfig) + tx := types.MustSignNewTx(prvA, signer, &types.LegacyTx{ + Nonce: nonce, + Gas: 21_000, + GasPrice: gasPrice, + To: &addrB, + Value: w3.I("1 ether"), + }) + + var txHash common.Hash + if err := client.Call(eth.SendTx(tx).Returns(&txHash)); err != nil { + // ... + } + + fmt.Printf("Sent tx: %s\n", txHash) +} + +// Send ERC20 token transfer (Wrapped Ether). +func ExampleClient_sendTokenTransfer() { + var ( + nonce uint64 + gasPrice *big.Int + ) + if err := client.Call( + eth.Nonce(addrA, nil).Returns(&nonce), + eth.GasPrice().Returns(&gasPrice), + ); err != nil { + // ... + } + + funcTransfer := w3.MustNewFunc("transfer(address receiver, uint256 amount)", "bool") + data, err := funcTransfer.EncodeArgs(addrB, w3.I("1 ether")) + if err != nil { + // ... + } + + signer := types.LatestSigner(params.MainnetChainConfig) + tx := types.MustSignNewTx(prvA, signer, &types.LegacyTx{ + Nonce: nonce, + Gas: 100_000, + GasPrice: gasPrice, + To: &addrWETH, + Data: data, + }) + + var txHash common.Hash + if err := client.Call(eth.SendTx(tx).Returns(&txHash)); err != nil { + // ... + } + + fmt.Printf("Sent tx: %s\n", txHash) +} + +// Subscribe to pending transactions. +func ExampleClient_subscribeToPendingTransactions() { + client, err := w3.Dial("wss://mainnet.gateway.tenderly.co") + if err != nil { + // ... + } + defer client.Close() + + pendingTxCh := make(chan *types.Transaction) + sub, err := client.Subscribe(eth.PendingTransactions(pendingTxCh)) + if err != nil { + // ... + } + + for { + select { + case tx := <-pendingTxCh: + fmt.Printf("New pending tx: %s\n", tx.Hash()) + case err := <-sub.Err(): + fmt.Printf("Subscription error: %v\n", err) + return + } + } +} + +// Rate Limit the number of requests to 10 per second, with bursts of up to 20 +// requests. +func ExampleClient_rateLimitByRequest() { + client, err := w3.Dial("https://rpc.ankr.com/eth", + w3.WithRateLimiter(rate.NewLimiter(rate.Every(time.Second/10), 20), nil), + ) + if err != nil { + // ... + } + defer client.Close() +} + +// Rate Limit the number of requests to 300 compute units (CUs) per second, with +// bursts of up to 300 CUs. +// An individual CU can be charged per RPC method call. +func ExampleClient_rateLimitByComputeUnits() { + // cu returns the CU cost for all method calls in a batch. + cu := func(methods []string) (cost int) { + for _, method := range methods { + switch method { + case "eth_blockNumber": + cost += 5 + case "eth_getBalance", + "eth_getBlockByNumber", + "eth_getCode", + "eth_getStorageAt", + "eth_getTransactionByHash", + "eth_getTransactionReceipt": + cost += 15 + case "eth_call": + cost += 20 + case "eth_getTransactionCount": + cost += 25 + default: + panic(fmt.Sprintf("unknown costs for %q", method)) + } + } + return cost + } + + client, err := w3.Dial("https://rpc.ankr.com/eth", + w3.WithRateLimiter(rate.NewLimiter(rate.Every(time.Second/300), 300), cu), + ) + if err != nil { + // ... + } + defer client.Close() +} + +// ABI bindings for the ERC20 functions. +func ExampleFunc_erc20() { + var ( + funcTotalSupply = w3.MustNewFunc("totalSupply()", "uint256") + funcBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256") + funcTransfer = w3.MustNewFunc("transfer(address to, uint256 amount)", "bool") + funcAllowance = w3.MustNewFunc("allowance(address owner, address spender)", "uint256") + funcApprove = w3.MustNewFunc("approve(address spender, uint256 amount)", "bool") + funcTransferFrom = w3.MustNewFunc("transferFrom(address from, address to, uint256 amount)", "bool") + ) + _ = funcTotalSupply + _ = funcBalanceOf + _ = funcTransfer + _ = funcAllowance + _ = funcApprove + _ = funcTransferFrom +} + +// Encode and decode the arguments of the balanceOf function. +func ExampleFunc_balanceOf() { + // encode + input, err := funcBalanceOf.EncodeArgs(addrA) + if err != nil { + // ... + } + fmt.Printf("encoded: 0x%x\n", input) + + // decode + var who common.Address + if err := funcBalanceOf.DecodeArgs(input, &who); err != nil { + // ... + } + fmt.Printf("decoded: balanceOf(%s)\n", who) + // Output: + // encoded: 0x70a082310000000000000000000000000a00000000000000000000000000000000000000 + // decoded: balanceOf(0x0a00000000000000000000000000000000000000) +} + +// ABI bindings for the Uniswap v4 swap function. +func ExampleFunc_uniswapV4Swap() { + funcSwap := w3.MustNewFunc(`swap( + (address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) key, + (bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) params, + bytes hookData + )`, "int256 delta") + + // ABI binding for the PoolKey struct. + type PoolKey struct { + Currency0 common.Address + Currency1 common.Address + Fee *big.Int + TickSpacing *big.Int + Hooks common.Address + } + + // ABI binding for the SwapParams struct. + type SwapParams struct { + ZeroForOne bool + AmountSpecified *big.Int + SqrtPriceLimitX96 *big.Int + } + + // encode + input, _ := funcSwap.EncodeArgs( + &PoolKey{ + Currency0: addrWETH, + Currency1: addrDAI, + Fee: big.NewInt(0), + TickSpacing: big.NewInt(0), + }, + &SwapParams{ + ZeroForOne: false, + AmountSpecified: big.NewInt(0), + SqrtPriceLimitX96: big.NewInt(0), + }, + []byte{}, + ) + fmt.Printf("encoded: 0x%x\n", input) + // Output: + // encoded: 0xf3cd914c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000 +} + +func ExampleFunc_DecodeReturns_getReserves() { + funcGetReserves := w3.MustNewFunc("getReserves()", "uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast") + output := w3.B( + "0x00000000000000000000000000000000000000000000003635c9adc5dea00000", + "0x0000000000000000000000000000000000000000000000a2a15d09519be00000", + "0x0000000000000000000000000000000000000000000000000000000064373057", + ) + + var ( + reserve0, reserve1 *big.Int + blockTimestampLast uint32 + ) + if err := funcGetReserves.DecodeReturns(output, &reserve0, &reserve1, &blockTimestampLast); err != nil { + // ... + } + fmt.Println("Reserve0:", reserve0) + fmt.Println("Reserve1:", reserve1) + fmt.Println("BlockTimestampLast:", blockTimestampLast) + // Output: + // Reserve0: 1000000000000000000000 + // Reserve1: 3000000000000000000000 + // BlockTimestampLast: 1681338455 +} + +func ExampleEvent_decodeTransferEvent() { + var ( + eventTransfer = w3.MustNewEvent("Transfer(address indexed from, address indexed to, uint256 value)") + log = &types.Log{ + Address: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + Topics: []common.Hash{ + w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + w3.H("0x000000000000000000000000000000000000000000000000000000000000c0fe"), + w3.H("0x000000000000000000000000000000000000000000000000000000000000dead"), + }, + Data: w3.B("0x0000000000000000000000000000000000000000000000001111d67bb1bb0000"), + } + + from common.Address + to common.Address + value big.Int + ) + + if err := eventTransfer.DecodeArgs(log, &from, &to, &value); err != nil { + fmt.Printf("Failed to decode event log: %v\n", err) + return + } + fmt.Printf("Transferred %s WETH9 from %s to %s", w3.FromWei(&value, 18), from, to) + // Output: + // Transferred 1.23 WETH9 from 0x000000000000000000000000000000000000c0Fe to 0x000000000000000000000000000000000000dEaD +} diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 766ab6fe..00000000 --- a/examples/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Examples - -The following example projects can help you understand `w3`: - -* [scan_blocks](scan_blocks/): Scan blocks blazing fast using batch requests. -* [token_balance](token_balance/): Fetch an accounts token balance and info in a single batch request. -* [uniswap_quote](uniswap_quote/): Get the best Uniswap V3 quote for the given token pair. - -Please [open an issue](https://github.com/lmittmann/w3/issues/new) if you -would like to see another example. diff --git a/examples/go.mod b/examples/go.mod deleted file mode 100644 index 7b05dc64..00000000 --- a/examples/go.mod +++ /dev/null @@ -1,37 +0,0 @@ -module examples - -go 1.22 - -require ( - github.com/ethereum/go-ethereum v1.14.8 - github.com/lmittmann/w3 v0.0.0 -) - -replace github.com/lmittmann/w3 => ../ - -require ( - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/StackExchange/wmi v1.2.1 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.1 // indirect - github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect - github.com/deckarep/golang-set/v2 v2.6.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/ethereum/c-kzg-4844 v1.0.0 // indirect - github.com/go-ole/go-ole v1.3.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/holiman/uint256 v1.3.1 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect - github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect - github.com/supranational/blst v0.3.11 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/time v0.7.0 // indirect - rsc.io/tmplfunc v0.0.3 // indirect -) diff --git a/examples/go.sum b/examples/go.sum deleted file mode 100644 index f6ecb976..00000000 --- a/examples/go.sum +++ /dev/null @@ -1,145 +0,0 @@ -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= -github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= -github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= -github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= -github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= -github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= -github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= -github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= -github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= -github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= -github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= -github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= -github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.14.8 h1:NgOWvXS+lauK+zFukEvi85UmmsS/OkV0N23UZ1VTIig= -github.com/ethereum/go-ethereum v1.14.8/go.mod h1:TJhyuDq0JDppAkFXgqjwpdlQApywnu/m10kFPxh8vvs= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= -github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= -github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= -github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= -github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= -github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= -github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/examples/scan_blocks/main.go b/examples/scan_blocks/main.go deleted file mode 100644 index 5a8e50d9..00000000 --- a/examples/scan_blocks/main.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -scan_blocks iterates over blocks with their transactions from a given start block. - -Usage: - - scan_blocks [flags] - -Flags: - - -start uint - Start block (default 10_000_000) - -h, --help - help for scan_blocks -*/ -package main - -import ( - "flag" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/lmittmann/w3" - "github.com/lmittmann/w3/module/eth" - "github.com/lmittmann/w3/w3types" -) - -var ( - // number of blocks to fetch in a single request - bulkSize = 100 - - // flags - startBlock uint64 -) - -func main() { - // parse flags - flag.Uint64Var(&startBlock, "start", 10_000_000, "Start block") - flag.Usage = func() { - fmt.Println("scan_blocks iterates over blocks with their transactions from a given start block.") - flag.PrintDefaults() - } - flag.Parse() - - // connect to RPC endpoint - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - // fetch blocks in bulk - calls := make([]w3types.RPCCaller, bulkSize) - blocks := make([]*types.Block, bulkSize) - - for i, txCount := 0, 0; ; i++ { - j := i % bulkSize - calls[j] = eth.BlockByNumber(new(big.Int).SetUint64(startBlock + uint64(i))).Returns(&blocks[j]) - - if j == bulkSize-1 { - if err := client.Call(calls...); err != nil { - fmt.Printf("Call failed: %v\r", err) - return - } - - for _, block := range blocks { - txCount += len(block.Transactions()) - processBlock(block) - } - fmt.Printf("\rFetched %d blocks with a total of %d transactions", i+1, txCount) - } - } -} - -func processBlock(b *types.Block) { - // Do something with the block and its transactions... -} diff --git a/examples/token_balance/main.go b/examples/token_balance/main.go deleted file mode 100644 index 4687cf92..00000000 --- a/examples/token_balance/main.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -token_balance prints the balance of an ERC20 token for a given account. - -Usage: - - token_balance [flags] - -Flags: - - -acc string - Account address (default "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - -token string - Token address (default "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - -h, --help - help for token_balance -*/ -package main - -import ( - "flag" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/lmittmann/w3" - "github.com/lmittmann/w3/module/eth" -) - -var ( - // smart contract functions - funcName = w3.MustNewFunc("name()", "string") - funcSymbol = w3.MustNewFunc("symbol()", "string") - funcDecimals = w3.MustNewFunc("decimals()", "uint8") - funcBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256") - - // flags - addrAcc common.Address - addrToken common.Address -) - -func main() { - // parse flags - flag.TextVar(&addrAcc, "acc", w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), "Account address") - flag.TextVar(&addrToken, "token", w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), "Token address") - flag.Usage = func() { - fmt.Println("token_balance prints the balance of an ERC20 token for a given account.") - flag.PrintDefaults() - } - flag.Parse() - - // connect to RPC endpoint - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - // fetch token details and account balance - var ( - name, symbol string - decimals uint8 - balance big.Int - ) - if err := client.Call( - eth.CallFunc(addrToken, funcName).Returns(&name), - eth.CallFunc(addrToken, funcSymbol).Returns(&symbol), - eth.CallFunc(addrToken, funcDecimals).Returns(&decimals), - eth.CallFunc(addrToken, funcBalanceOf, addrAcc).Returns(&balance), - ); err != nil { - fmt.Printf("Call failed: %v\n", err) - return - } - - fmt.Printf("%s balance of %s: %s %s\n", name, addrAcc, w3.FromWei(&balance, decimals), symbol) -} diff --git a/examples/uniswap_quote/main.go b/examples/uniswap_quote/main.go deleted file mode 100644 index 6e2cca22..00000000 --- a/examples/uniswap_quote/main.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -uniswap_quote prints the UniSwap V3 exchange rate to swap amontIn of tokenIn for -tokenOut. - -Usage: - - uniswap_quote [flags] - -Flags: - - -amountIn string - Amount of tokenIn to exchange for tokenOut (default "1 ether") - -tokenIn string - Token in address (default "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - -tokenOut string - Token out address (default "0x6B175474E89094C44Da98b954EedeAC495271d0F") - -h, --help - help for uniswap_quote -*/ -package main - -import ( - "flag" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/lmittmann/w3" - "github.com/lmittmann/w3/module/eth" - "github.com/lmittmann/w3/w3types" -) - -var ( - addrUniV3Quoter = w3.A("0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6") - - funcQuoteExactInputSingle = w3.MustNewFunc("quoteExactInputSingle(address tokenIn, address tokenOut, uint24 fee, uint256 amountIn, uint160 sqrtPriceLimitX96)", "uint256 amountOut") - funcName = w3.MustNewFunc("name()", "string") - funcSymbol = w3.MustNewFunc("symbol()", "string") - funcDecimals = w3.MustNewFunc("decimals()", "uint8") - - // flags - addrTokenIn common.Address - addrTokenOut common.Address - amountIn big.Int -) - -func main() { - // parse flags - flag.TextVar(&amountIn, "amountIn", w3.I("1 ether"), "Token address") - flag.TextVar(&addrTokenIn, "tokenIn", w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), "Token in") - flag.TextVar(&addrTokenOut, "tokenOut", w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F"), "Token out") - flag.Usage = func() { - fmt.Println("uniswap_quote prints the UniSwap V3 exchange rate to swap amontIn of tokenIn for tokenOut.") - flag.PrintDefaults() - } - flag.Parse() - - // connect to RPC endpoint - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - // fetch token details - var ( - tokenInName string - tokenInSymbol string - tokenInDecimals uint8 - tokenOutName string - tokenOutSymbol string - tokenOutDecimals uint8 - ) - if err := client.Call( - eth.CallFunc(addrTokenIn, funcName).Returns(&tokenInName), - eth.CallFunc(addrTokenIn, funcSymbol).Returns(&tokenInSymbol), - eth.CallFunc(addrTokenIn, funcDecimals).Returns(&tokenInDecimals), - eth.CallFunc(addrTokenOut, funcName).Returns(&tokenOutName), - eth.CallFunc(addrTokenOut, funcSymbol).Returns(&tokenOutSymbol), - eth.CallFunc(addrTokenOut, funcDecimals).Returns(&tokenOutDecimals), - ); err != nil { - fmt.Printf("Failed to fetch token details: %v\n", err) - return - } - - // fetch quotes - var ( - fees = []*big.Int{big.NewInt(100), big.NewInt(500), big.NewInt(3000), big.NewInt(10000)} - calls = make([]w3types.RPCCaller, len(fees)) - amountsOut = make([]big.Int, len(fees)) - ) - for i, fee := range fees { - calls[i] = eth.CallFunc(addrUniV3Quoter, funcQuoteExactInputSingle, addrTokenIn, addrTokenOut, fee, &amountIn, w3.Big0).Returns(&amountsOut[i]) - } - err := client.Call(calls...) - callErrs, ok := err.(w3.CallErrors) - if err != nil && !ok { - fmt.Printf("Failed to fetch quotes: %v\n", err) - return - - } - - // print quotes - fmt.Printf("Exchange %q for %q\n", tokenInName, tokenOutName) - fmt.Printf("Amount in:\n %s %s\n", w3.FromWei(&amountIn, tokenInDecimals), tokenInSymbol) - fmt.Printf("Amount out:\n") - for i, fee := range fees { - if ok && callErrs[i] != nil { - fmt.Printf(" Pool (fee=%5v): Pool does not exist\n", fee) - continue - } - fmt.Printf(" Pool (fee=%5v): %s %s\n", fee, w3.FromWei(&amountsOut[i], tokenOutDecimals), tokenOutSymbol) - } -} diff --git a/func_test.go b/func_test.go index 73137a39..74930210 100644 --- a/func_test.go +++ b/func_test.go @@ -3,7 +3,6 @@ package w3_test import ( "bytes" "errors" - "fmt" "math/big" "strconv" "testing" @@ -16,106 +15,6 @@ import ( "github.com/lmittmann/w3/w3types" ) -func ExampleNewFunc_balanceOf() { - // ABI binding to the balanceOf function of an ERC20 Token. - funcBalanceOf, _ := w3.NewFunc("balanceOf(address)", "uint256") - - // Optionally names can be specified for function arguments. This is - // especially useful for more complex functions with many arguments. - funcBalanceOf, _ = w3.NewFunc("balanceOf(address who)", "uint256 amount") - - // ABI-encode the functions args. - input, _ := funcBalanceOf.EncodeArgs(w3.A("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B")) - fmt.Printf("balanceOf input: 0x%x\n", input) - - // ABI-decode the functions args from a given input. - var ( - who common.Address - ) - funcBalanceOf.DecodeArgs(input, &who) - fmt.Printf("balanceOf args: %v\n", who) - - // ABI-decode the functions output. - var ( - output = w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe") - amount *big.Int - ) - funcBalanceOf.DecodeReturns(output, &amount) - fmt.Printf("balanceOf returns: %v\n", amount) - // Output: - // balanceOf input: 0x70a08231000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b - // balanceOf args: 0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B - // balanceOf returns: 49406 -} - -func ExampleNewFunc_uniswapV4Swap() { - // ABI binding for the Uniswap v4 swap function. - funcSwap, _ := w3.NewFunc(`swap( - (address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) key, - (bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) params, - bytes hookData - )`, "int256 delta") - - // ABI binding for the PoolKey struct. - type PoolKey struct { - Currency0 common.Address - Currency1 common.Address - Fee *big.Int - TickSpacing *big.Int - Hooks common.Address - } - - // ABI binding for the SwapParams struct. - type SwapParams struct { - ZeroForOne bool - AmountSpecified *big.Int - SqrtPriceLimitX96 *big.Int - } - - // ABI-encode the functions args. - input, _ := funcSwap.EncodeArgs( - &PoolKey{ - Currency0: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), - Currency1: w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F"), - Fee: big.NewInt(0), - TickSpacing: big.NewInt(0), - }, - &SwapParams{ - ZeroForOne: false, - AmountSpecified: big.NewInt(0), - SqrtPriceLimitX96: big.NewInt(0), - }, - []byte{}, - ) - fmt.Printf("swap input: 0x%x\n", input) - // Output: - // swap input: 0xf3cd914c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000 -} - -func ExampleFunc_DecodeReturns_getReserves() { - funcGetReserves := w3.MustNewFunc("getReserves()", "uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast") - output := w3.B( - "0x00000000000000000000000000000000000000000000003635c9adc5dea00000", - "0x0000000000000000000000000000000000000000000000a2a15d09519be00000", - "0x0000000000000000000000000000000000000000000000000000000064373057", - ) - - var ( - reserve0, reserve1 *big.Int - blockTimestampLast uint32 - ) - if err := funcGetReserves.DecodeReturns(output, &reserve0, &reserve1, &blockTimestampLast); err != nil { - // ... - } - fmt.Println("Reserve0:", reserve0) - fmt.Println("Reserve1:", reserve1) - fmt.Println("BlockTimestampLast:", blockTimestampLast) - // Output: - // Reserve0: 1000000000000000000000 - // Reserve1: 3000000000000000000000 - // BlockTimestampLast: 1681338455 -} - func TestNewFunc(t *testing.T) { tests := []struct { Signature string diff --git a/w3vm/example_test.go b/w3vm/example_test.go new file mode 100644 index 00000000..f0be1dc6 --- /dev/null +++ b/w3vm/example_test.go @@ -0,0 +1,351 @@ +package w3vm_test + +import ( + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + gethVm "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/params" + "github.com/lmittmann/w3" + "github.com/lmittmann/w3/module/eth" + "github.com/lmittmann/w3/w3types" + "github.com/lmittmann/w3/w3vm" +) + +var ( + addrA = common.Address{0x0a} + addrB = common.Address{0x0b} +) + +// Execute an Ether transfer. +func ExampleVM_simpleTransfer() { + vm, _ := w3vm.New( + w3vm.WithState(w3types.State{ + addrA: {Balance: w3.I("100 ether")}, + }), + ) + + // Print balances + balA, _ := vm.Balance(addrA) + balB, _ := vm.Balance(addrB) + fmt.Printf("Before transfer:\nA: %s ETH, B: %s ETH\n", w3.FromWei(balA, 18), w3.FromWei(balB, 18)) + + // Transfer 10 ETH from A to B + vm.Apply(&w3types.Message{ + From: addrA, + To: &addrB, + Value: w3.I("10 ether"), + }) + + // Print balances + balA, _ = vm.Balance(addrA) + balB, _ = vm.Balance(addrB) + fmt.Printf("After transfer:\nA: %s ETH, B: %s ETH\n", w3.FromWei(balA, 18), w3.FromWei(balB, 18)) + // Output: + // Before transfer: + // A: 100 ETH, B: 0 ETH + // After transfer: + // A: 90 ETH, B: 10 ETH +} + +// Execute an ERC20 token transfer with faked token balance (Wrapped Ether). +func ExampleVM_fakeTokenBalance() { + vm, err := w3vm.New( + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: w3types.Storage{ + w3vm.WETHBalanceSlot(addrA): common.BigToHash(w3.I("100 ether")), + }}, + }), + ) + if err != nil { + // ... + } + + // Print WETH balance + var balA, balB *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&balA); err != nil { + // ... + } + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrB).Returns(&balB); err != nil { + // ... + } + fmt.Printf("Before transfer:\nA: %s WETH, B: %s WETH\n", w3.FromWei(balA, 18), w3.FromWei(balB, 18)) + + // Transfer 10 WETH from A to B + if _, err := vm.Apply(&w3types.Message{ + From: addrA, + To: &addrWETH, + Func: funcTransfer, + Args: []any{addrB, w3.I("10 ether")}, + }); err != nil { + // ... + } + + // Print WETH balance + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&balA); err != nil { + // ... + } + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrB).Returns(&balB); err != nil { + // ... + } + fmt.Printf("After transfer:\nA: %s WETH, B: %s WETH\n", w3.FromWei(balA, 18), w3.FromWei(balB, 18)) + // Output: + // Before transfer: + // A: 100 WETH, B: 0 WETH + // After transfer: + // A: 90 WETH, B: 10 WETH +} + +// Execute an ERC20 balanceOf call with raw a [w3types.Message] using the +// messages Func and Args helper. +func ExampleVM_call() { + vm, err := w3vm.New( + w3vm.WithFork(client, nil), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: w3types.Storage{ + w3vm.WETHBalanceSlot(addrA): common.BigToHash(w3.I("100 ether")), + }}, + }), + ) + if err != nil { + // ... + } + + receipt, err := vm.Call(&w3types.Message{ + To: &addrWETH, + Func: funcBalanceOf, + Args: []any{addrA}, + }) + if err != nil { + // ... + } + + var balance *big.Int + if err := receipt.DecodeReturns(&balance); err != nil { + // ... + } + fmt.Printf("Balance: %s WETH\n", w3.FromWei(balance, 18)) + // Output: + // Balance: 100 WETH +} + +// Execute an ERC20 balanceOf call using the [VM.CallFunc] helper. +func ExampleVM_callFunc() { + vm, err := w3vm.New( + w3vm.WithFork(client, nil), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: w3types.Storage{ + w3vm.WETHBalanceSlot(addrA): common.BigToHash(w3.I("100 ether")), + }}, + }), + ) + if err != nil { + // ... + } + + var balance *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&balance); err != nil { + // ... + } + fmt.Printf("Balance: %s WETH\n", w3.FromWei(balance, 18)) + // Output: + // Balance: 100 WETH +} + +// Execute an Uniswap V3 swap. +func ExampleVM_uniswapV3Swap() { + var ( + addrRouter = w3.A("0xE592427A0AEce92De3Edee1F18E0157C05861564") + addrUNI = w3.A("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984") + + funcExactInput = w3.MustNewFunc(`exactInput( + ( + bytes path, + address recipient, + uint256 deadline, + uint256 amountIn, + uint256 amountOutMinimum + ) params + )`, "uint256 amountOut") + ) + + // mapping for the exactInput-function params-tuple + type ExactInputParams struct { + Path []byte + Recipient common.Address + Deadline *big.Int + AmountIn *big.Int + AmountOutMinimum *big.Int + } + + encodePath := func(tokenA, tokenB common.Address, fee uint32) []byte { + path := make([]byte, 43) + copy(path, tokenA[:]) + path[20], path[21], path[22] = byte(fee>>16), byte(fee>>8), byte(fee) + copy(path[23:], tokenB[:]) + return path + } + + // 1. Create a VM that forks the Mainnet state from the latest block, + // disables the base fee, and has a fake WETH balance and approval for the router + vm, err := w3vm.New( + w3vm.WithFork(client, big.NewInt(20_000_000)), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: w3types.Storage{ + w3vm.WETHBalanceSlot(addrA): common.BigToHash(w3.I("1 ether")), + w3vm.WETHAllowanceSlot(addrA, addrRouter): common.BigToHash(w3.I("1 ether")), + }}, + }), + ) + if err != nil { + // ... + } + + // 2. Simulate a Uniswap v3 swap + receipt, err := vm.Apply(&w3types.Message{ + From: addrA, + To: &addrRouter, + Func: funcExactInput, + Args: []any{&ExactInputParams{ + Path: encodePath(addrWETH, addrUNI, 500), + Recipient: addrA, + Deadline: big.NewInt(time.Now().Unix()), + AmountIn: w3.I("1 ether"), + AmountOutMinimum: w3.Big0, + }}, + }) + if err != nil { + // ... + } + + // 3. Decode output amount + var amountOut *big.Int + if err := receipt.DecodeReturns(&amountOut); err != nil { + // ... + } + + fmt.Printf("AmountOut: %s UNI\n", w3.FromWei(amountOut, 18)) + // Output: + // AmountOut: 278.327327986946583271 UNI +} + +// Execute a message sent from the zero address. +// The [w3types.Message] sender can be freely chosen, making it possible to +// execute a message from any address. +func ExampleVM_prankZeroAddress() { + vm, err := w3vm.New( + w3vm.WithFork(client, big.NewInt(20_000_000)), + w3vm.WithNoBaseFee(), + ) + if err != nil { + // ... + } + + balZero, err := vm.Balance(w3.Addr0) + if err != nil { + // ... + } + + _, err = vm.Apply(&w3types.Message{ + From: w3.Addr0, + To: &addrA, + Value: balZero, + }) + if err != nil { + // ... + } + + balance, err := vm.Balance(addrA) + if err != nil { + // ... + } + + fmt.Printf("Received %s ETH from zero address\n", w3.FromWei(balance, 18)) + // Output: + // Received 13365.401185473565028721 ETH from zero address +} + +// Trace a message execution to obtain the access list. +func ExampleVM_traceAccessList() { + txHash := w3.H("0xbb4b3fc2b746877dce70862850602f1d19bd890ab4db47e6b7ee1da1fe578a0d") + + var ( + tx *types.Transaction + receipt *types.Receipt + ) + if err := client.Call( + eth.Tx(txHash).Returns(&tx), + eth.TxReceipt(txHash).Returns(&receipt), + ); err != nil { + // ... + } + + var header *types.Header + if err := client.Call(eth.HeaderByNumber(receipt.BlockNumber).Returns(&header)); err != nil { + // ... + } + + vm, err := w3vm.New( + w3vm.WithFork(client, receipt.BlockNumber), + ) + if err != nil { + // ... + } + + // setup access list hook + signer := types.MakeSigner(params.MainnetChainConfig, header.Number, header.Time) + from, _ := signer.Sender(tx) + + accessListTracer := logger.NewAccessListTracer( + nil, + from, *tx.To(), + gethVm.ActivePrecompiles(params.MainnetChainConfig.Rules(header.Number, header.Difficulty.Sign() == 0, header.Time)), + ) + + if _, err := vm.ApplyTx(tx, accessListTracer.Hooks()); err != nil { + // ... + } + fmt.Println("Access List:", accessListTracer.AccessList()) +} + +// Trace the execution of all op's in a block. +func ExampleVM_traceBlock() { + blockNumber := big.NewInt(20_000_000) + + var block *types.Block + if err := client.Call(eth.BlockByNumber(blockNumber).Returns(&block)); err != nil { + // ... + } + + vm, err := w3vm.New( + w3vm.WithFork(client, blockNumber), + ) + if err != nil { + // ... + } + + var ops [256]uint64 + tracer := &tracing.Hooks{ + OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + ops[op]++ + }, + } + + for _, tx := range block.Transactions() { + vm.ApplyTx(tx, tracer) + } + + for op, count := range ops { + if count > 0 { + fmt.Printf("0x%02x %-14s %d\n", op, gethVm.OpCode(op), count) + } + } +} diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index dc9fbd1c..218420f9 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -810,149 +810,3 @@ func BenchmarkTransferWETH9(b *testing.B) { } func ptr[T any](t T) *T { return &t } - -func ExampleVM_transferEthFromZeroAddress() { - client, err := w3.Dial("https://rpc.ankr.com/eth") - if err != nil { - // handle error - } - defer client.Close() - - vm, err := w3vm.New( - w3vm.WithFork(client, nil), - w3vm.WithNoBaseFee(), - ) - if err != nil { - // handle error - } - - recipient := w3vm.RandA() - - _, err = vm.Apply(&w3types.Message{ - From: common.Address{}, - To: &recipient, - Value: w3.I("1 ether"), - }) - if err != nil { - // handle error - } - - balance, err := vm.Balance(recipient) - if err != nil { - // handle error - } - - fmt.Printf("Balance: %s ETH\n", w3.FromWei(balance, 18)) - // Output: Balance: 1 ETH -} - -func ExampleVM() { - var ( - addrEOA = w3.A("0x000000000000000000000000000000000000c0Fe") - addrWETH = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - addrUNI = w3.A("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984") - addrRouter = w3.A("0xE592427A0AEce92De3Edee1F18E0157C05861564") - - funcExactInput = w3.MustNewFunc(`exactInput( - ( - bytes path, - address recipient, - uint256 deadline, - uint256 amountIn, - uint256 amountOutMinimum - ) params - )`, "uint256 amountOut") - ) - - type ExactInputParams struct { - Path []byte - Recipient common.Address - Deadline *big.Int - AmountIn *big.Int - AmountOutMinimum *big.Int - } - - encodePath := func(tokenA common.Address, fee uint32, tokenB common.Address) []byte { - path := make([]byte, 43) - copy(path, tokenA[:]) - path[20], path[21], path[22] = byte(fee>>16), byte(fee>>8), byte(fee) - copy(path[23:], tokenB[:]) - return path - } - - client, err := w3.Dial("https://rpc.ankr.com/eth") - if err != nil { - // handle error - } - defer client.Close() - - // 1. Create a VM that forks the Mainnet state from the latest block, - // disables the base fee, and has a fake WETH balance and approval for the router - vm, err := w3vm.New( - w3vm.WithFork(client, nil), - w3vm.WithNoBaseFee(), - w3vm.WithState(w3types.State{ - addrWETH: {Storage: w3types.Storage{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), - }}, - }), - ) - if err != nil { - // handle error - } - - // 2. Simulate a UniSwap v3 swap - receipt, err := vm.Apply(&w3types.Message{ - From: addrEOA, - To: &addrRouter, - Func: funcExactInput, - Args: []any{&ExactInputParams{ - Path: encodePath(addrWETH, 500, addrUNI), - Recipient: addrEOA, - Deadline: big.NewInt(time.Now().Unix()), - AmountIn: w3.I("1 ether"), - AmountOutMinimum: w3.Big0, - }}, - }) - if err != nil { - // handle error - } - - // 3. Decode output amount - var amountOut *big.Int - if err := receipt.DecodeReturns(&amountOut); err != nil { - // handle error - } - - fmt.Printf("amount out: %s UNI\n", w3.FromWei(amountOut, 18)) -} - -func ExampleVM_Call() { - client := w3.MustDial("https://rpc.ankr.com/eth") - defer client.Close() - - addrWETH := w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - addrEOA := w3.A("0x000000000000000000000000000000000000c0Fe") - - vm, err := w3vm.New( - w3vm.WithFork(client, nil), - w3vm.WithState(w3types.State{ - addrWETH: {Storage: w3types.Storage{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - }}, - }), - ) - if err != nil { - // handle error - } - - balanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") - var balance *big.Int - if err := vm.CallFunc(addrWETH, balanceOf, addrEOA).Returns(&balance); err != nil { - // handle error - } - fmt.Printf("%s: Balance: %s WETH\n", addrEOA, w3.FromWei(balance, 18)) - // Output: - // 0x000000000000000000000000000000000000c0Fe: Balance: 1 WETH -} From 608b244c54f353335112d91dbeeaabc75c73e89c Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:32:53 +0200 Subject: [PATCH 5/9] docs: added VM tracing and testing section (#195) * docs/components: added support for geth tracing module * added tracing + testing section + rpc overview improvements --------- Co-authored-by: lmittmann --- docs/components/DocLink.jsx | 3 + docs/pages/examples/index.mdx | 1 + docs/pages/index.mdx | 4 +- docs/pages/rpc-overview.mdx | 48 +++++- docs/pages/vm-overview.mdx | 20 +-- docs/pages/vm-testing.mdx | 184 +++++++++++++++++++++- docs/pages/vm-tracing.mdx | 58 ++++++- docs/public/_redirects | 3 + docs/public/assets/call-trace.png | Bin 0 -> 342411 bytes docs/public/{ => assets}/ef-logo-dark.svg | 0 docs/public/{ => assets}/ef-logo.svg | 0 w3vm/example_test.go | 121 +++++++++++++- w3vm/vm.go | 2 +- 13 files changed, 419 insertions(+), 25 deletions(-) create mode 100644 docs/public/assets/call-trace.png rename docs/public/{ => assets}/ef-logo-dark.svg (100%) rename docs/public/{ => assets}/ef-logo.svg (100%) diff --git a/docs/components/DocLink.jsx b/docs/components/DocLink.jsx index 1bc3c2c0..866787b4 100644 --- a/docs/components/DocLink.jsx +++ b/docs/components/DocLink.jsx @@ -10,6 +10,9 @@ const pkgNameToPath = { 'web3': 'github.com/lmittmann/w3/module/web3', 'w3types': 'github.com/lmittmann/w3/w3types', 'w3vm': 'github.com/lmittmann/w3/w3vm', + 'hooks': 'github.com/lmittmann/w3/w3vm/hooks', + 'tracing': 'github.com/ethereum/go-ethereum/core/tracing', + 'logger': 'github.com/ethereum/go-ethereum/eth/tracers/logger', } export const DocLink = ({ title, id }) => { diff --git a/docs/pages/examples/index.mdx b/docs/pages/examples/index.mdx index 29fe4852..e720a1ba 100644 --- a/docs/pages/examples/index.mdx +++ b/docs/pages/examples/index.mdx @@ -28,6 +28,7 @@ * **Call ERC20 balanceOf** with raw a `w3types.Message` using the `Message.{Func,Args}` helper ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-Call)) * **Call ERC20 balanceOf**, using the `VM.CallFunc` helper ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-CallFunc)) * **Prank** a sender ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-PrankZeroAddress)) +* **Trace calls** (and opcodes) of a transaction ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceCalls)) * **Trace** the execution to obtain the access list ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceAccessList)) * **Trace** the execution of all op's in a block ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceBlock)) diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx index 78e51067..0988face 100644 --- a/docs/pages/index.mdx +++ b/docs/pages/index.mdx @@ -40,6 +40,6 @@ go get github.com/lmittmann/w3 ## Sponsors
- EF Logo - + EF Logo +
diff --git a/docs/pages/rpc-overview.mdx b/docs/pages/rpc-overview.mdx index 39f25aa3..b11981d0 100644 --- a/docs/pages/rpc-overview.mdx +++ b/docs/pages/rpc-overview.mdx @@ -40,8 +40,8 @@ if err := client.Call( - #### Why send batch requests? - Most of the time you need to call multiple RPC methods to get the data you need. When you make separate requests per RPC call you need a single round trip to the server for each call. This can be slow, especially for remote endpoints. Batching multiple RPC calls into a single request only requires a single round trip, and speeds up RPC calls significantly. +#### Why send batch requests? +Most of the time you need to call multiple RPC methods to get the data you need. When you make separate requests per RPC call you need a single round trip to the server for each call. This can be slow, especially for remote endpoints. Batching multiple RPC calls into a single request only requires a single round trip, and speeds up RPC calls significantly. ## Call @@ -54,8 +54,48 @@ if err := client.Call( ## Subscribe -Coming soon... +`w3.Client` supports subscriptions through the and methods. Subscriptions can be used to listen to events, emitted by the Ethereum node. + +### Subscriptions + +* `eth.NewHeads(ch chan<- *types.Header)`: Subscribe to new block headers. +* `eth.NewLogs(ch chan<- *types.Log, q ethereum.FilterQuery)`: Subscribe to new logs. +* `eth.PendingTransactions(ch chan<- *types.Transaction)`: Subscribe to new pending transactions. + +#### Example: Subscribe to Pending Transactions + +Subscribe to new pending transactions ([Playground](https://pkg.go.dev/github.com/lmittmann/w3##example-Client-SubscribeToPendingTransactions)): + +```go +pendingTxCh := make(chan *types.Transaction) +sub, err := client.Subscribe(eth.PendingTransactions(pendingTxCh)) +if err != nil { + // ... +} + +for { + select { + case tx := <-pendingTxCh: + fmt.Printf("New pending tx: %s\n", tx.Hash()) + case err := <-sub.Err(): + fmt.Printf("Subscription error: %v\n", err) + return + } +} +``` ## Error Handling -Coming soon... +If one or more calls in a batch request fail, `Client.Call` returns an error of type . + +#### Example: `w3.CallErrors` + +Check which RPC calls failed in a batch request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3##example-Client-BatchHandleError)) +```go +var batchErr w3.CallErrors +if err := client.Call(calls...); errors.As(err, &batchErr) { + // handle call errors +} else if err != nil { + // handle other errors +} +``` diff --git a/docs/pages/vm-overview.mdx b/docs/pages/vm-overview.mdx index cd28242b..724372ae 100644 --- a/docs/pages/vm-overview.mdx +++ b/docs/pages/vm-overview.mdx @@ -1,8 +1,8 @@ # VM - is a super simple to use Ethereum Virtual Machine (EVM), built on top of `go-ethereum/core/vm.EVM`. It supports **tracing**, **state forking** via RPC, and can be used for simulation, debugging EVM execution, or testing Smart Contracts. + is an easy-to-use Ethereum Virtual Machine (EVM), built on top of `go-ethereum`'s `vm.EVM`. It supports **tracing**, **state forking** via RPC, and can be used for simulation, debugging EVM execution, or testing Smart Contracts. -* **State forking** via RPC, or custom state fetchers enable transaction simulations or Smart Contract tests on live, or historic chain state. +* **State forking** via RPC or custom state fetchers enables transaction simulations or Smart Contract tests on live, or historical chain state. * **Tracing** of EVM execution is supported via `go-ethereum/core/tracing.Hooks`. @@ -66,17 +66,17 @@ fmt.Printf("Balance: %s ETH\n", w3.FromWei(balance, 18)) ## Setup -A new VM instance is created using the `w3vm.New` function, which accepts various options to customize the VM behavior. +A new VM instance is created using the `w3vm.New` function, which accepts various options to customize the VM behavior: -* `WithChainConfig(cfg *params.ChainConfig)`: Sets the chain configuration. If not set, the VM falls back to the Mainnet configuration. +* `WithChainConfig(cfg *params.ChainConfig)`: Sets the chain configuration. If not provided, the VM defaults to the Mainnet configuration. * `WithNoBaseFee()`: Forces the EIP-1559 base fee to 0. * `WithBlockContext(ctx *vm.BlockContext)`: Sets the block context for the VM. -* `WithHeader(header *types.Header)`: Sets the block context for the VM based on the given header. -* `WithState(state w3types.State)`: Sets the pre state of the VM. If used with `WithFork`, the pre state overrides the forked state. -* `WithStateDB(db *state.StateDB)`: Sets the state database for the VM, that is usually a snapshot obtained from `VM.Snapshot`. -* `WithFork(client *w3.Client, blockNumber *big.Int)`: Forks state from a live Ethereum client at a specific block number. -* `WithFetcher(fetcher Fetcher)`: Sets the fetcher for the VM. -* `WithTB(tb testing.TB)`: Enables persistent state caching when used together with `WithFork`. +* `WithHeader(header *types.Header)`: Configures the block context for the VM using the provided header. +* `WithState(state w3types.State)`: Sets the pre-state of the VM. When used with `WithFork`, the pre-state overrides the forked state. +* `WithStateDB(db *state.StateDB)`: Specifies the state database for the VM, typically a snapshot from `VM.Snapshot`. +* `WithFork(client *w3.Client, blockNumber *big.Int)`: Forks state from a live Ethereum client at the specified block number. +* `WithFetcher(fetcher Fetcher)`: Assigns a fetcher to the VM. +* `WithTB(tb testing.TB)`: Enables persistent state caching when used in conjunction with `WithFork`. ## Execution diff --git a/docs/pages/vm-testing.mdx b/docs/pages/vm-testing.mdx index 8ba6c523..59fbf179 100644 --- a/docs/pages/vm-testing.mdx +++ b/docs/pages/vm-testing.mdx @@ -1,3 +1,183 @@ -# Test Contracts +# Contract Testing -Coming soon... +`w3vm` can be used to test Smart Contracts in Go utilizing Go's handy testing and fuzzing features. + + +`w3vm` **does not** natively support Smart Contract compilation. + + +## Compile Smart Contracts + +The first step to testing a Smart Contract is usually to compile it to bytecode. There are a number of third party packages that provide compiler bindings in Go: + +* [`go-solc`](https://github.com/lmittmann/go-solc): Go bindings for the Solidity compiler (`solc`) +* [`go-huffc`](https://github.com/project-blanc/go-huffc): Go Bindings for the Huff Compiler (`huffc`) +* [`geas`](https://github.com/fjl/geas): The Good Ethereum Assembler + + +## Setup a `w3vm.VM` + +Before a Smart Contract can be tested with a `w3vm.VM` instance, its bytecode must be deployed to the VM. This can be done in two ways, depending on whether constructor logic is present. + +### Without Constructor Logic + +If the Smart Contract does not require constructor logic, its runtime bytecode can be directly set as the bytecode of an address: + + +```go +contractRuntime = w3.B("0x...") +contractAddr := w3vm.RandA() + +vm, _ := w3vm.New( + w3vm.WithState(w3types.State{ + contractAddr: {Code: runtime}, + }), +) +``` + +### With Constructor Logic + +If the Smart Contract requires constructor logic, the constructor bytecode must be sent in a standard deployment transaction (`w3types.Message`) without recipient: + +```go +contractConstructor := w3.B("0x...") +deployerAddr := w3vm.RandA() + +vm, _ := w3vm.New() +receipt, err := vm.Apply(&w3types.Message{ + From: deployerAddr, + Input: contractConstructor, +}) +if err != nil || receipt.ContractAddress == nil { + // ... +} +contractAddr := *receipt.ContractAddress +``` + +### Custom State + +The state of the VM can be fully customized using the `w3vm.WithState` option. This allows, e.g., setting a balance for addresses that interact with the Smart Contract. State can also be modified after the VM is created using the [state write methods](/vm-overview#writing-state). + +### State Forking + +If the tested Smart Contract interacts with other existing contracts, the VM can be configured to fork the state at a specific block number (or the latest block). This enables testing contracts in a real-world environment. + +```go +client := w3.MustDial("https://rpc.ankr.com/eth") +defer client.Close() + +vm, err := w3vm.New( + w3vm.WithFork(client, big.NewInt(20_000_000)), + w3vm.WithNoBaseFee(), + w3vm.WithTB(t), +) +if err != nil { + // ... +} +``` + + +`w3vm.WithTB(t)` can be used in tests or benchmarks to **cache state**. The VM persists this cached state in `{package of test}/testdata/w3vm/`. This is particularly useful when working with public RPC providers, as it reduces the number of requests and significantly speeds up test execution. + + + +## Testing + +Testing Smart Contracts with `w3vm` follows the standard Go testing patterns using the package `testing`. By integrating `w3vm` into your tests, you can simulate blockchain interactions and validate Smart Contract behaviors within your test cases. + +#### Example: Test WETH `deposit` Function + +Test of the WETH `deposit` function. + +```go +func TestWETHDeposit(t *testing.T) { + // setup VM + vm, _ := w3vm.New( + w3vm.WithState(w3types.State{ + addrWETH: {Code: codeWETH}, + addrA: {Balance: w3.I("1 ether")}, + }), + ) + + // pre check + var wethBalanceBefore *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceBefore); err != nil { + t.Fatal(err) + } + if wethBalanceBefore.Sign() != 0 { + t.Fatal("Invalid WETH balance: want 0") + } + + // deposit (via fallback) + if _, err := vm.Apply(&w3types.Message{ + From: addrA, + To: &addrWETH, + Value: w3.I("1 ether"), + }); err != nil { + t.Fatalf("Deposit failed: %v", err) + } + + // post check + var wethBalanceAfter *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceAfter); err != nil { + t.Fatal(err) + } + if w3.I("1 ether").Cmp(wethBalanceAfter) != 0 { + t.Fatalf("Invalid WETH balance: want 1") + } +} +``` + + +## Fuzz Testing + +Fuzzing Smart Contracts with `w3vm` leverages Go's fuzz testing capabilities to automatically generate a wide range of inputs for your contracts. By incorporating `w3vm` into your fuzzing tests, you can effectively discover vulnerabilities and unexpected behaviors in your Smart Contracts. + +#### Example: Fuzz Test WETH `deposit` Function + +Fuzz test of the WETH `deposit` function. + +```go +func FuzzWETHDeposit(f *testing.F) { + f.Add([]byte{1}) + f.Fuzz(func(t *testing.T, amountBytes []byte) { + if len(amountBytes) > 32 { + t.Skip() + } + amount := new(big.Int).SetBytes(amountBytes) + + // setup VM + vm, _ := w3vm.New( + w3vm.WithState(w3types.State{ + addrWETH: {Code: codeWETH}, + addrA: {Balance: w3.BigMaxUint256}, + }), + ) + + // Pre-check WETH balance + var wethBalanceBefore *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceBefore); err != nil { + t.Fatal(err) + } + + // Attempt deposit + vm.Apply(&w3types.Message{ + From: addrA, + To: &addrWETH, + Value: amount, + }) + + // Post-check WETH balance + var wethBalanceAfter *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceAfter); err != nil { + t.Fatal(err) + } + + // Verify balance increment + wantBalance := new(big.Int).Add(wethBalanceBefore, amount) + if wethBalanceAfter.Cmp(wantBalance) != 0 { + t.Fatalf("Invalid WETH balance: want %s, got %s", wantBalance, wethBalanceAfter) + } + }) +} +``` diff --git a/docs/pages/vm-tracing.mdx b/docs/pages/vm-tracing.mdx index 288bc214..2fda29be 100644 --- a/docs/pages/vm-tracing.mdx +++ b/docs/pages/vm-tracing.mdx @@ -1,3 +1,59 @@ # Tracing -Coming soon... +Tracing can give detailed insights into the execution of EVM contracts. `w3vm.VM` supports tracing via `go‑ethereum`'s . + +## Usage + +A `tracing.Hooks` can be passed to , , and . These methods can also be called with multiple hooks at the same time. + +#### Example: Trace Calls and OpCodes of an Execution + +`w3vm` contains a powerful call an opcode tracer that can be used gain detailed insights into the execution of EVM contracts ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-Trace)): + +```go +callTracer := hooks.NewCallTracer(os.Stdout, &hooks.CallTracerOptions{ + ShowStaticcall: true, + DecodeABI: true, +}) +vm.ApplyTx(tx, callTracer) +``` + +![Example Call Trace](/assets/call-trace.png) + +#### Example: Generate an Access List + +Access list tracing using `go-ethereum`'s ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceAccessList)): + +```go {2-8} +// setup access list tracer +signer := types.MakeSigner(params.MainnetChainConfig, header.Number, header.Time) +from, _ := signer.Sender(tx) +accessListTracer := logger.NewAccessListTracer( + nil, + from, *tx.To(), + gethVm.ActivePrecompiles(params.MainnetChainConfig.Rules(header.Number, header.Difficulty.Sign() == 0, header.Time)), +) + +if _, err := vm.ApplyTx(tx, accessListTracer.Hooks()); err != nil { + // ... +} +fmt.Println("Access List:", accessListTracer.AccessList()) +``` + +#### Example: Trace the Execution of all OpCodes in a Block + +Trace the execution of all op's in a block ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceBlock)): + +```go {2-7} +// setup block op's tracer +var opCount [256]uint64 +tracer := &tracing.Hooks{ + OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + opCount[op]++ + }, +} + +for _, tx := range block.Transactions() { + vm.ApplyTx(tx, tracer) +} +``` diff --git a/docs/public/_redirects b/docs/public/_redirects index e69de29b..923e35ff 100644 --- a/docs/public/_redirects +++ b/docs/public/_redirects @@ -0,0 +1,3 @@ +/vm /vm-overview +/rpc /rpc-overview +/abi /helper-abi diff --git a/docs/public/assets/call-trace.png b/docs/public/assets/call-trace.png new file mode 100644 index 0000000000000000000000000000000000000000..94edee30ef93f14457c44a10ae8f28b17c73afac GIT binary patch literal 342411 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%0Ah(TEaa$pL5m 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

`DI235X7F1DaVQ< z*Mt(op-$R6*~(bp2r7*gOm&0K_TwKte$T~JvDme%JUi3C@=7It#XQe_%Qilk2(OCo4*_pNAx{1f94YP zKkvm(sh)HG0A@hwKwAq{92XZ22G81S-G7GJGtLG3kA%!2P%0GsMUVvHGP%-g3o=Xy zrxw_$h`t7p%#HOF@H~${q3qhUBeqhRqXVl3=NUiX$!qcm77KWp4;t&9v0vfH&__L5l0s z-&axT3m#hg3n*M*bYTIFjkO^F%l~?wV6Fp3sH}LfF?s6-iS7}aV#y3A?rfFrn zJ6rrex0|QrIHRXxs}HVD@cOVwh0%*LEIZ}_gVJ1y%S`PZ%u~^aGRsqu(LWoy(3g$c zY!>R!Gj|O>>Htjt8rVG5W~V?)FbJTn-kT#h#1tZ8nCk7Fv~WrvB*p^Nz?7m!sq+uQ ziR?yvicLn~YTIs#QK>pA4sqQxDOk%wWe@~?!85>{gVK>bj->Bwucala3dxDg>!bA? ztl!;ju?`HS@F)NWloeP*N7Kj_AQWim=z~b|x89#tfD}OaFFPNZ+_WCh6ViMy?|sh`WzZxmD$wEnT`yww(l*-n&9xJ*ZTSQp_@Fs|%Z{yZY4`XOaK~`bdI4v#aPT58#^O=OMs@*fXGw(BsQcUzcpd)bD zVv-9wLlJBKaCa-J!#cL>A8n-MyFTyIG{+kx6%O?91HJ|-gwfPRPFj@e!k1xeMm->_ zL_k1gthB1^e{ySDQcWM_D1ru+v8!X`^m98#4;c98Mqv}N^ZlEUX6h`8BKWyz8=DQihvo(&?L3 z>D`ybA6|@%$WF=Y%~1kwstc^9N+ zA{=>$YYJ2ZM?n^yf_ur_wo8r?6ahrJY@q=d@6+Ldh!;e)E`*AU!j__eDRRkWh+Mpr z+ECg_auZoO0nL55`v;nPp#bSKQE8;FEoh^-SMjACOWC|5XC)bxwTF1D7j3V=?O;fS zEWG=@P?*Mptqujj!>b#>Y{`5*$#B!V*g@>{=G93#D#{{$49*)0%1xdffT>eO{GxIt z&Hu@$WfyAiC_?dl!KGpCgn(ffqOsn}plf9R79O(3SJbz%nF&0eM?h7_jHo+%Y>ueC zQW~P1Dodxi0I1Zxarrp5bhY4uM~ujZX`KR!!1e&n;ZsO3Da|NVMyhg8q5=Uj@e_|50&@8Jo#ewZvXxhSnxwD|~(+Yz>)DB=6;VXCGI z{oCN%pRWBDKDposz$o>bbl+j?yK@u}C56IoFaQ_@Ma(!rH29m)j(2~)T~(df*$fK; za6wmujzJMK^WA98A@;=jfcbUVBLJX`KdpP$IlcCegCP@nFFzBV4n6lbjFpQN=UBpwh~4u=}#PT*48-DPkW< z#C3@Tpom5qjjUN+(fz-k=i_bpk=+#+LCqMQOMf*zF~Zf^ZY8wZ=91*GGP6&bs}D-0 zkYgr3X}%b}tX#E9R__HRG1VhCoM+!EVZ@K8|1`k(=ie97g9EG>;!|1u>A;i%JV&CL zSwS!ojpAmaV{8|1Ll;^37aXk0MUSQB$p2NU4_(t8ofb!!db7B)Sr`in5cEoIJZe;o zR_)$s^JWRxKigj0>~LWGX@$be)S@H|l>A!!w6Uh9A5j4|zx$|hZwPmnR1}o;!Hk3< zhum{E3mJ>GD_YaFVEsXJ)3F?l;s%4pdbcs#tfUqbh%yWwS6t(`FX$9Drhf>dyOF`m z$n?@5Ej&h3oRk*_)UGZuVy3chd{L^;e<%A-jz1R-Qoa=!m@#{}8{cyz)+}&;NX9ah zw~LMxWrDv`%@(2H>ArM_&A1JmGrZ~P=_^X?Xq{-yXU?1%7#cdYUZBKm8NRG!l|bM3ML@hPG2(Qse+&UfEW;DSFU0q4$|UChv|qJ)I1q#6iL? zOXfSoM)X6n+S^4lpmz}&59^w~Oh*I5JBxK58zanyzx#P9@;_RDuF4JnyAv4cxTeK; zmvHyR8u%iOxbU*!;f7z9E?Wl6%C{#0G0sexb0FSCxwf|N^a!&g)$&`Za}E!xxLs36 zxa!!yyG>9iYLUkw&Mdm10u1(tw9rK4qHBZEbrif^6(VPi#%U&AJjsv-OXkXE! zxNF3`k9`V~)GOly&5#PAT1FzPPk!lq8%zl|cPyt0(%GLeDChBaq5l8ata z7*Rk=h+V~iyzC@LsSG4sH{VJ_h4-#7zh1VAjE>N>A$A%#kX3z;PNxw6C=4zm59Jp8 zAR0leyBPZSX1N^neihm zU0|kK{jx0t>7cBIcQ*8@;cYBocSY4IhSI9;J>8b_9GplNd~vF3kCIB!jCoOYu$8AM zdIj7R86}WvcfgT}wvGhv&7Tj=Zq};R#$vY`r|4Wb2XSzv*2qq86Qd)N26y+^eR=EO z8${N&fIUF_&onKpS+DZ>z-AC&=)(iPur`)e7@!BHWgx5srHAmT)>~|B{~Hk5=g^#% z`6?#fs2UBc3StBg;9l{Ir8g%kF;XXLt?09S62ff^LkqA_eZl^t%|&$!=A?{72VZ65 z*MGqSAlVk@BQbZtOB=WW@o$84Hl>8V;csjk|oph8#WBAb#z<&uReDP6GU{vkZLsW^6X&PZ4s77 zYd^pe%~xk}9sFaN!>ZV@d)F>!OhN91hl2@N4DhmgdUPjcxq861pPEQ-A9jj#OAT41 z8h`cQNq_(!f>>V94AQq3oh8JrSQj9jc5U1*b5L4m=8vDWF@06;Y zyQzCSOz*$j>c`b?hn?@m|IB;82koIG16ivk`#%)|2F2)zl`92YMcKdGL1bZp_T~&F zM4%Wh)`QHzmWBTI5p`qT$SY8rGA%?C^MGdav8pM6scck{-MDO9bCQ-PaQZoPdee>` zJh*g28Xmai)F6(jmi0Q|%OO&HI1yo23Cd_XDRVgK9g&~II%K9(V-_%;mdS3|2jU-r z8WM5>XO9v8NF`+eBcoh6Ntyu(bNP3Ro6xNTx!0pZfRkU0y2&Ll1D^|7t|Z%pq;3{{ zg=@3|!axxPF2bUKxLV;0HqjT;!ifl4P6H(+AQuOaPQe{4t2jL*dAT?x%beHdqPQM1 zTt`uIA1sJ|>sd}|Idfd~COC8eSOt9-6^YcOL{s7{{5RcfCVjRkyFKD^S~qVVoz%N2 zz5KYY1H#kFe=r+264|F1O1_$JQ>f?iuZ)0wE$?dbWW5FO9%NcHJt=aLI>6KnQBs30 zA+5TUIRQO@K+9eVk-V}Cm5NJp8rZ%}96tTuV#mhi^^+&xYx8z0Z`t7A-!Nj$zGH88 z%@}(=FI+H9VPBJ9yx1YBB;;7byMDu+w6U$C@^;4mfhYs^2oWBND9SNu?qs$eAoUc7 zI!GUqmn@J%_YIqUqoZ%5w6vB#@g5@@QH=<2$?z%iR@rbWwfTqq&!6kjzYyq7oId^V zQzXfL!R>WpY>gL;NMfL)Qzs>k9tq44A(vz9H>9fI7aO<|BuJ_5n3Z7%qRe4n?7-;7 zALSDn@qlSSZVEi7#Aia4pNT}N90N(O!(Cr3A1L#rj0DhU(k{uBh4hl;wqWZgGpY%n z2p&a?tNaiIjGGzDNP$C#qM@SHooL$_t0LAFHs;In?i{~;6^xP7LQyxc-3ziAs<7=;{v;?$2)$Efpgc0f z%M~Y*GP{cjj_fr-UA{kH;Zq$oQIYaAkQ-1vT1Dks!z!~uMcmn^_T=sX;Kv8AN`G^g zs39hfqdRXW=!)Mn+Eaq0C>@sfU-3Ulp|VvLWYmX7s#hJeM|-x--o9{tQQ^;`fc)?s zI66m7=pV5|Ko&xRVyd{hrEg2kMQRourFwqpfH%(ZAFuXpM7ku49+_x)y+>#-;wyj$ znHp^8)0NP^1{n!ctcTCr%P6W0ta9&_6ofkgC#W}?F|X6^`Sq7MrCX;i=)7O8w;$<< z@Be9CMWE%T?;G?1uVC&+bU)B|Xv!ONor3M-Z!a+ZYJmit$F8i6cMQ>(m<;a5nN!w2 z0A6Djg4ML^_#PRS&E|xpvSPC8WZBqs!&hZh0H1RXM|_@pE6wP{%az=Bn{WP9x31%7 z|Lt|MWh$qFTf`o9MbN zwjNgSNUM?EWu{81B2RR0y~pNTxrSS&_o|*L=kjkrJx0FP)m2kIH}lsXe`UqE)6eJE z_`TDesvZ8`XuH!n2bce?sW&E#F%EEA{+m2m&A|k zORxVgp;6U_k;Bf-|EkyE|E8LX(>iL!7pn4%!c;?}%>&bZ|I(sHtku^|G&-&WYJ+ViDNh1ua{BzGmeCN_`jlGiu>XJy&F z$U)C4CvCGlySLcd&(0~*0#s2)1HYgLO9}%+-jB$Se3|p?m{~}6id9eVZ$^( zahv6o`fJnkb7fZ6J(|9s{Gna0)vXO}bGJQR7#@A5PyE%YDE0m02A)mNC`!3x7QQ`k zOV7N_`IA!T|JftYUt_g?>C;87)d`nQ#hBl#-1Ow?yFY5J2h~wr!6QMI4` zx8854KJC9gatu*GATJ;Sd_*3|z;74HjA-|H2<=(IFeI#AMSKdf9K@Jnsx0T6cblnh#En8&E zE}L*%&{e^2!!lfvRlRN6wAKK7M8Aj}TQsGwA0(#KyG*ojPi`M@)(JCO|u3d7gIi-9gl41}oiRt*Rw zBYVM7$&Owi7D-3sZ4vCFWjWIKAQqXzjFGSvBbc9-6|@K=5A1ZJ%9X_jtP7;E2GR$O z6G)%mol~YH=syx=2)`yE2Rimi*H@(Ipwt38GH386?05)@78xY0qj(jv$ot8YCyvDd z$P>u5QvQ-aLBLJ|0(~+P%@!DvtaE`eLc4~Xe<&YA&%8z?!hnNQ2^LAiYqv&q{3v5W zRDUdqKb`J=irhi_E3-xl*}{CUw#Ff-EN=;{~F{?o_m;GE7BJjJWHo= zFculkCG*!FMS#atGxNhD3!>4cM(6}02kU$<=*bTLX>Cn@?a0o$wd2xnu4xDBQ#S-o z%7S4lnPVr9!dNr2{Tu$ddUd!=agVGW{_}%@;rW$oI@~KOSvtK(#H7Ff>>g33(xB6c zQ^_M04gP9ovj61Cu}yY&Zm9i2+5P;6y8Bz7>eBvnS@#AJJNB72jO%(}z>&BFl*3`E zhvIVoJQ{h`b-_0WWgKNIFT912dGQe3R3;d*8Tk8N?3vl4nxC7<}6OlVVfUtz~Q zFH`x$XXu0t$MX^$!L&I@vZKnW2Dm0z@y5SJKvFEVnRGXd)S;f$c$`w3^NF#2vvd+b$W@&lCo)+#gCXtTSs9e@!j!~=I zv06|hhTL|a^n9Z4W(O9|G;U*1m5g<_>DXd1(GEq0s_eQA2!|YN8f%34wX9;WQ50?# zqMJEAS}3N+3v%D+iFqGy!}4<+1q3=oR@Yxd6})4D#=$e6GME><_T{IJ+r+`ZwYu?y*4wWO!*o zB?`;GBVK*m@W8*EX`uI?%h?$tO7)(*?*m-2^5yBT<20>BMMaG3H|AzxNGB_k1phj3 zQ|(jJ{^PpaUteBmqsU;7N8MZB5`O~0xw4=F8(MLw_cD$7b&jN7V9N zvaeC)*q#{Ra>s8uR_psS)6`*6D*dgv&C27q9V(q0I!f+-Y02%#queY^C0MBYt@f*7 zO;7w*@rp!NuD;c{10pdf!f1YrXVEbq6WViFmsrG|h4_Xv8zya!7+W0bgL%||q1im? z2ag7`p^U0tVkN;^x!rvBTyQ29CjJ1@m%hmBNgQZ`39AWYV5a2j{%PT$d~Fa40Q}NI zi@h3Trpy>cSgERMjM%Kw?j`dn$gv+>W_<1ePbBx1J z(%1k)^wZN1M$8+8888cN>M6)K`-g43-r?oSL4@n#ers0a2Ef3}iA$FzHMMKYbSEj} zvEOFeQ=ePe`5U!$ZXEz7V8ap`1zEuiWcBswLyb*35V^ibk6!(Fli6ADoIx7bkj4Y2 zj6`ts;RA4(h+T*5epqLO+z+;AH*pVg-=^8cVpARWm}t3}Sy{@8-zi8-|HY4^=pQA1 zz+`k@pSpaY4DxquR=*@~G~fr!MO1ciGUH#&XMqYey?AvF>t>O+{~P(_8B_Vw9SS6G zpYsXmn9<~Ke!5__SeIqdubW;mLuExEqSe7na|GfKo{ZqW7mibzOEJi38q?GbcqFt` z?T6YbXe;fL_~jPhD)y_MX*R0-xTnA8_tBp1>cRDI$fqI{w$ zDssV&8MGzXvDy0e5TxoWWI_ar)w2&D67?@*?~5ST!=piSTL6HrEi=3mN&zoT zu%YCv(z$xIF-w6S0UnP^OFRBoGeSa6gr4l&%CK>&Y=;Vk@kDk#Hbqr56xy3O4m_0H z(sbY?3(z~5&pMM*2oJmyik^`yNe$oINJG<}!^%&q6chnRI?Ck(*$7RC^X_{_jZ zHQ>7y&sY#wOtUS3uNi@2eHl%}wXvR?@FhYp5hdbxeJ6%i_Mp{?W<3z}hPZ+uuR%zH zhB?$cx{gs$Jcg9AoR)8mayD>kPgKStibakuDt>T))ERvRx3Z51|94;(zu`fd>O-%Z$(BMbVDIwIRJfjT$+!{+uM|5I@914FIL%IQ`KahI?}c?8CXF9=0>$fasBS@%;HEZCnhsd5p~d z&B-Ux9Pm#bn=+6Gz-kFk|0&?$UZ$hkM=|jsAwm)tSNtF6plEa(&>_&Ps3p~s%-@q6U>JFtGSke{6z@T9+SmO`?4aP1+US^~=IB1r zS1f!%IH+PUSimi%C5OJeJj=VZeGU~gs|2mKMdl6ot6m)?hCHEY7=u1ttM3$^q0GbF z{4-Zm&LN`CYP)H3$_o+quSF+itrf*r9>ub=VcaJ%q0R4T{sD-cK{@)$)#0wP+zzT_ zlySR2Ml}n3L4kxJUeK>i`zES}+96|;pEDCC0f_3%>w6|@k>64KK-{k50Jz=PeGJdP z7ef+_E9PzSmoMtK4@l~vIYmop5#s^+vrQ-KL|aGMD9z>qv5C%n;cUzHIC?%>TxT+c zlSztf#faw75Q*f`uo@4$G5ai-%~{)a9GNjz$NkI-9@y1;Lww@v`NR*Zf0DXxGaD>~ zroJ?54@f5$kJ}!_crN-oQ6Co) zn;AUa#fnq4)7lPLTA#sgu<7r$x0Hu=>7q<&lTlm&7$?^q#twD}XFCtD_v;gE%acyQ zTu{wq0q>E7zt!fKcrmLTLmc3D3(G*WC*$Lc^9%h8%jERrHQ`F!fhF^9lR!?!&T)J` zaE&4qi_k308PyHlrlqLpeKf=l*_H6m+r4f*V& z5QQRjqBMH>t`RE#0E6xB0yMfdgdZmvF( z-1jblmm$#;)Fo8yc|Rx0az#oE>?ch>>yMcx(xzwOb~cI;B=Y4)yWa^%^)J}y)ycd{ zWLmr@(~SuzpN!tK+4g?MWF|~yHwGM{NKR3~{Tx{qhIg$vahoq$;zIpQSuWHLA~fzl zdlF21lysriP3T~?jkiAjzRyx8XRpQ(S0(mLEdf}R`eTdPrCBklsXpd!9_c7shO9W+ z-SF}2;?>0nYGNoedDkOy8{9nQm#EHLmtB?cW8Psa2DYV1TxY|Q_<}@({3t{ORLT?) za&gHcb5r-)jqIuZk=Nf?godHPyfGAxexMb>%P&$-Aq?zy{jm3K^LM+8d|_NC%F zt#*8wNL%5k|LkZ&9}ew6>n+R7#We=SqP_k2*kRZa!mJ6TkF=~DLlCO>6-9Tc3^+E? zS%q_|HHkS3RmQKoy#S;C*5b~D@S?u;+Zk#T`uVuVe;(PfS=C}yoq#0jd3Ua!|ANfI z&5#CNb6)JPMP!eG5}GQF&nCR){u`z+ajnZ{*dptdH;$H{q*e=;GHIB;J`Te9r@u|( znTs<3%QtMP(rXtjUavkTlOsQtNba2OQn})&8^)cq+HhEMbQqoYZdCW10gQXJaH>KZZN(sK41I|>-2kG zSW*OHRfWv*_hvTyNyNioeRg8EgdtRc5V14`vQ2v2qt6u2I$O(a!8bDa++7D0vKE`L ze?IylHfrr>Roz*l4)a4C8b1=uHqn}8Htc&?(P{P@3&DcOE8rf;)aGyx}WCF=>+piZL zueqIoz`swp6T1_nC*gmo5C$bR&YV5_nx(BGa?EBgJWIJgg3a7xwG;&^x2FxH!%q4_ zHnbFQ%)U2RgxwVIfdvAsTR7GxJbhXSk<|&gF(Fu3jOG(bC!=8Fc_kvHLZ#YlUr#ot z&|^vX|I>{+Gb+%;wWE4N(PI`# zhloAYEWF80;ie2-i!bP$LoEj{n|a~o63P!#uO=!TPpoJwoiwKv1#Bp}Esdp282igs zHfJSe8CpL++^MFit06SC#Dcj>;my042421TT(MP~A!6Qm0q1OM>C4#065%Q+o@G2-PLqCRwHZU_^G|W_znWEDyC6Npkxp!STCpnYgO3 z8TKQ6z3H`vwIK&sZpFKy`MN@hOi8t99}Di2iP!Ro86#)FTAlKV&nlaoI~y5k`Se@( zJjDn&L!bnNo}vaM1PMtgVU!(gJg@J=D$I7+KezrA5-984;9ybDKq8wm1>}+2PKPV-^E0q#5*>CPM9|A!0U)Jq5|<( z&pS3o7D+)1vOH~OlG17m3s;HU)ZL_PcKg;R_r44&<8GS}o_It6r11?mrwsJs+p=F&Q88M?u2A62`|+&C8{fH__1~)$Ex?X`lihgd5Q0jbo1ol44tk|1vC}BG3`&NJ zhdKZXV^Ojua0WskO)yR=H6PF2QzeM@C(Pn6p4- zree_qp*Gz;+c1)|W>EGKCAtC7QCOceGbK?Py0id^=x zX5{w5lS97f3|8@;s(;PPLWkb7P0Jo+w)$ z%p&aZAzBPMV4BT>Gi8RbkYt-P7zel8nU%ct0}U|RVK2+kgm1K^sq3HXTy>xl1KO0? znNpYS0ft*#=*(Z5r@@g5hQ>R4-e|Pd(!2CzVw;G5=LA!q;BBG-q`Pbv8l5PD zHc=U47Jz_r?a$n~w&Y`a0wUa4uoY-&kG)u*?7n!hFaJc=e-IWSEagB*6q1M9tCz>j zq?0S!%8E(Abn$ws0=^whaX@FL%S1ks0{Nv>&WjH%5Jp+R{rhM3wi_#k`AmPi=) zWe@dQB2xNax>x$lV}59D-=^&bUz||=Wz09Hjai2QXHe@f6e;ufRQDjLBB#J)OwrG0 z56`3M?$n+;z~j&@xJX7MB^dWC0aX4p$KjG#ViRp}vt5ON2z2Ob%}A<$nb27_FLZ z{s*IoU4|A8R=IbtHqbwM2KG}lAHbul-`#8svZ@-8BxVme8c4zL2cpu8qA#*PrACx? zrZmALV|l2IG5}J_S|&-5%xz(-Kp!CsNXbKJ92nIJ9Mb0KnL^Zvne@KAMLu6$PHI?> z&zA}O_GNjK+JD33tZQ~Y2U?btQYA6u6IV9j^mI^wlekKu0%4hng5=936!K}R`j`O$ z`ZGwJ;`znAw)UaZRwsKPg%k@irkVSBb>>DBRgvzXVo6>;a}ewmum_-v1bI4IAOx`v zq>Kz)(H5lQfzHcs8yG@X9WzZTP&7bIcrWZa;5LZGF>3?CFqdfc@7lF4RH;lw0o~s* z>VS5+OOpu}*~iYTU`;K%anzuFVi>l0krmjcd&;pNlQkUt<1%u->+vi2143ZP7Fx&z z=5FM~$aDvJobm>D%ZK`c!ctkG&a8)|=#}1sO#y6Y5pxNlmD$sl(#PZ+#>eXFbroVP zPu8WLCvnTD1UU%B%Koc!{FeD31^xK(W69NruM=-jcK!Kh1BlY5EdK)h;y(Nxcmaqk z;#z!x#+R||`oxn52IuvywL#NVL-~1voRn!aE82$~sv;g}ET>%&yr(Gj#fyU)`_0x7koz!ZUI1!0N|B(ts7Xjp!(IB3nMt zJ<*W?)?hhe#3|&i3JF3e-8uS|ol3{22?=wwrf8*yWVPLByq?<8KHvPJVY`-I9kjHn zr+e9*Q7^zXRrLFI^IK2seF#UpK+fs>FzcN}BwnA)%fi@G#7AuWq1O6JVOFADFTfM} zCXC&HoO&l`LoV(_NDugs5}!y7xeCP*7E|erv^NAC=F& zHNRiXx$ttOm^fc}`TfQc!R4unMY~98O_q?YAY!P;Uk6^sD&fQFTo?dB$GB*MU%N(~ zORb&LrbKW>fp8xDgYM4_#Y_QoZvpypZ1EqFV>vFv$K1>P)HI@uLjVybBzT zdEZWk{2v=o0WZKL~$$rQ!`O*xHpaaov0j@GXEYxFer z3kxh?9jI8G(#AQx_aWAaW6z=iUb#?zxc-w=85%nM+(%{k+t;t7kUP^qh$|Uv4o6qU zJus$Xk_x`1nct4vJ(gVYE!A#Rw@y&DYvw5Y9nm*_OEw^-ZroF-Gosg|6zJogdFhc; zR_8iZ=PVKw5+P-B@$v+>0f)C4E_qO2>{J;UTWI-KwO+mLyf2D+RIPo;p7dKo(zm)o zLDBv13s1N>#j2e(6|j`5pas%UL=3Vzun;gu{Lf+jTKAn3INPf;4i$t>+?O9B2cEP# z7p6ka86r~`6zdK4&baUrr)!9x*D|lPFkA%ym<{o4G;0J%=8A&_1K1yoSq~s^9x8;G|PwZr!K&utHhC8--`kaWvVK=JMDczdqZIE*stH-m)5K?(XqEYGKf0p)WAZvE_vhyAr_(lq8wn-xozW~*Fr-_ zNZru6v*(i;ECPW@5hXQLj`|qQ*RL7;y%>PCTrBOhIVHIiUmFiz^D89Ww^oS2DP+Ps@}1#1X}UIL*L6q z!C$xVY8t??0;#tYdtDuASYiM zQ(xcus;chVe?>wx(n8;#aB0&k@CZJnU?&tqJscmvz&1+yQ3s%1hZL05o>kqdYh<}P zs6D|u^zev;q$IWweqTFlm6@3~p}vsnzTY*IBW9hzv{de6)2_y>7yJ$6>&y64R_(X? z9m+s}VH7y#(yW%Y9+!rE;n3|z;74^d{jlF!ZHnguSNEv3!l&lOjYB;PwQ9SoH~e$y z8~}aqC;rlQptJ+10KQ?SI!3x4=#N*%>xrW%4WhY^UO%%J*A*j5Ktl{}OBLs+g+ZiR z76=1POF?>HdE;%AZfvHlP^DaQraEVZdJpSB;`n}ZgEvC0Uq639m%LxIbTKoLGI;3P zH?UTnplQ;vS>T;JZ=)&_Kd+lcp+Se{+Tt{dZ`}QQQ|fVZ8%()}NI?1t5dv78!GIEz z2*UV%lr4=DcfyO)WL7^ksJ#RtKng;UmE10t7FRaLQzno%p>aKbdb2+y27n6%`RXWd z1Vp^LT^AR3p-Y<>V5~*EBk@sO07|y;x^TSOLngdiqTK~3NGJ`Q_IG9ZH^|Uu3b%n7 z#W8&42$*-wDpX)4A%LYTq<9icg5pWwAklcg4&AN@=61*~dKI^|>X zWa%&xojK7?s5+%r*eJ*h83PB2%e~hfJtLLjrIR)^w5eteUSI1b9Ot705t>Fg4(0NV zM#{+M+DQj9>DM7j)L}CCXkc2gJfG4>WY2Ef?i?Akng<5ww)9!fFnA=vH9%Zs$4O4L z)JE(bip7`a&!1u72QrcZyM<5bVw@sR4H9)5Y9w3SDz8ok80@ApM9+u%^5VkqSyP5B zVlwqjQzD|m{EtbAkNx)s_E2s}lvmcoNM4U@l|3}DXG3w^{)kepOwB+P z0J3&8FnFivn*aI?*;n>~AO`h|J}znjAinLfSrVc}O=$K+>pU_x+6zZJ%k{JiOwE6o zd-=izhhC=5i?#ep|J;3&+f|3bL!*1A@wz5l(3kFYE;8!G2RwD^)CgFLdR>*GmN>=Sa=g#>t_nacH&nR&p3yG2is5#66@B04PLMvRWMg_Gfnp0r87cWMVlRWeq+ z8+`7-wO&kSVsd`cN>6`vcF{@Z4!ayWh{z5v$lXjS2423LxV$!e?}MQ}20oA3Ux1T? z+ti*f!Xp{O8)<5)B1#K}*e2%d(Z6>;y(r1gU~K!igtQ~IlYMneLabI&M+s}-s<(n; z&rhn+lt^FMBVg)XQ*A*!+YbmP zuCXt$?vw%Dh7M;vDk0h&c*FkEAu(}%V-+BKfiZtfJ`m>b?=LqV^C$^5@7{Uc%jwX~ zV(=!!x)YR_$)2s2Ek&`hI_=h#cMj)Yu54U@(r6Ev54A{QPyep0a)!_pS2KDs@kR*$ zTnnU#CD=$_DZ;}gp{*wtOhP)0{osc(-Qo?lwjDRSP#NI~A=!jDpz-)JTktsHp+8qz z#;%f#xWofbB&wW`Xvt0EZS5W;0$QrQ+85Vz zY0O1hgJ(1ucoi){Pxt=gJOFOGX+Wmekxr4*+8sIB^Qz_QOQ(oBUZS`(d)WWH#imDl z5a^+X`LlB0-md${35nLi_My4Id?NzO+&-08ehhL=);Ly+6n$K)J$wHcWP)IW=Tt&l`;!j~_ok zm!#}0hCTbgaCeXExKw!w3>+z`@%UDH1EH(AmeNg$PPyCM3+Kg5MX(^23513 z#FF0{?i|^FcMc`7hK{*{S3mAWd*$csTNrh2W?QdENpW!|sP8FOYDz<#_76yo9P6tT zIqb4Q@4;wlO+Z!v?Y4s{{k_}~+)|7kE?=J9zwMzjD})ONaN(-l+EzK3D9e(VI?Njj ztss7E6`pv`a38_1lY^&p=-jN=?va!Ph&BsKzRghXc04vqkRq_ip{&;7&{X;y{9yhe zU{bFs?4?C`AX;_1d^7IdNeZ~LS3$kpAfP$cGH}Cx5_$jgZ|`3kY|7QGQ`LHNW=_r? z((G~ljk}M(G2Zqo3U{6<0mcY$y`sZIdo`SxKYZ{?jJbVh&#sOJXzGL<3jk9F1E7m3 zY!~*vK^IEz-{tdRP9Hii?_M*`n6p<(C95fHHG%Trl264I7oRL*o`LC~Q>ywK)h|+SOS3PZKhqX9L2oPT(*btrNG(H2 zX=2S%9dp&?+nC2CdNoG-PaEm>e!c5ygYnbUk%@}?A9fs~UWIzu#fCmWRYKDhV3b$u zTd^#HjKxU4sFfF*J_Z)Ow)bgT_})s^YZk(+${aK|yXygCX+?V);iH%6ZxnAo#mLYQ zY5Z^gy5g5`*ua~-O8U9BLK-D+xdmVwHuLS0ZzJW|ob6{Pur1@p zD3nwQj!0@yuZicC%#v^>{zf7y5^_XdO%{3t{wT{z(j@Oh&{KWwy;wqT0uf1>k&IQ-ojd$zIo6*#eb zm;Dz&+U@V8?wLBp&q~c`+b?yT3GjDyThOn^9e-d(I$g0kx@Wm~vB|Gp5FSh%hZebj zWOwY_*Ry1!#nL4>AR(G9q-=_~xQqNQ+OWtRBaJu9=y}PS%Em`5k3`gdjPVYK6=ZyV6c)fd7vL1LocUROzywrgUkYE8ps>Ma8y0t5Vha z`mZN_LWBdQAj=u7lfXHaI88j0QDk9q6E}*sVLj609Ubh9r?8cHH!{r3JFXY$oB1Lng!?{|*> zOxUdh#ohm*Qo=sncbOqg)|r25yWWhq)~Q*2oYF4G<{PLkMT4M z%-k-+@#rfqE}M&j6p`DX0c#n)oSyFfbkmFF13{APvrQQwV{xqrMoCvx{$tC(p(B-h z0|jkV?Tu~^!VbJ0)1OXCrf_}lRkYr{d9(j}KdgHZgk5|y6qZoTUa{^I^tOo2;0*}_ zvcincC~}|igSus4hOjlwKwcOAZ2RNZO+Sx66qmc?2QV9lV3Itx1BQIVu}=PQjEiI3 zn3Paj_3EN-@2opl>xKVa?N_lZHvikL4q*DUe5c9`Eu7f-Hht&CAlI{3ueLxaTxZNQ zm0|>H-Cmnbn6Sre)(nPg@Cjp?>jWL`L*pOX5BAm06)9s$N!K54|7yKmn`;FBP3bV% zPk$%xsQ%9T{YshMR|oTz+7xr5+;x)|{-{@MpfdJX7pueZpFh&95GBSWA9k|?cJ-LL#)>(5479%F%0M6Qa{G3M2)_{>GzP8X4)jJXi3gTq{ zcWQj(#psLphH@d9g2_ZQPGcE*S=L{Or4){T$YW(lgcr`)5i$V2!2WnWZH!_m9HAH@ zo(;PZ8X7gjaXu!>bK?TqHpaSB;+Hr!P^%^ zb^rIlkKT^`!l)iyGr3&E3?dHaccBcocyV?bde$BdIuQ};+EGqpCbDeOtsLKy*t)vz zJ9ael+<#^TF&bbygVk?Q_#n*vv4sL;T`XSGkdvOX!mGMGaB~eUd@9^F76+m+K>`*1 zg6yG72tv=0`#wDNY;hY!gGWnx|5Y8ZR^d=NZ*h%Jb0f!lHMbkq&fBW0zox8B4}`hY zd;lKd$&Iey9xBrdXv#=a_c>0w_{@P>o<#13@7>a6Q6dr`K=reah?D^nciT@3@}(xBtJ4tYlNj-ZD~V zb}F-hA|ox5nUSmpQ6vpXMoA@-nancENEt24IH?pGMj}!gzx#21KG*g8es8z$b^H8r zo#&an->=tm9LHlFU*9xDy9K3IUXs-e8dT&!TMqSaX7(TRdeEW^;8q39E}RTMg_c`c zp$88A+15UL>zzTyL6Im>*qRVWRu$j{wN0=59bo_w-2o7pawpYUm$93L{N`pA7@c|w z%%>mf0qK3I~3wD4zW z$-#KeSoAS6@bfIzx@YSmJO`g1EcM*SARYaQ9p9d*s_NjSLSnmI(U2Q(umZh!h3}~! zxuLXS-u30(0nG8{S|czzx%~x7PnpUwPJi3q->W4u2`fj!pMWPHae+WYr#E}?>gvi4 z_$eSaWo#OPZy7+#$;AmJ?0E9+_Dy%ohKIxiPEfwQiSr1nz|?C)Iw4AEMrO+5L-`}L zv~*G2?VWSz<_wC!KMZa#udjDF4ereMRw#%X0}>?83SULbf~E=r=c4hExltrV(0CBr zU;rWl*|n^t+OtieC`l>FHT#UIzj0M)3Ns5iZX~$@QO&sH#cWi>kfbfiOCwK+>kaum zm|haNT6u%xDE1l4h!;nN%Sgm`)QghI`To9V{Fi2bx8YjcuW-yeb0NM~He9DE#={;z zc2lgMPL1wpgZ;X)=BS2GdRrS5EIgal15nt_<>1gcuL^hHU9q`1dwc6|_^g56qb9=ZAm=3abUg0johI$fDx^@u7(X3-=O)%|_exWGGDMku{0~cUgq{T*fqCqpBZYAXb|}4+&+->FMV)dLPHw zDnn{AMJiGR_Kf-Lluz!U_ z)Z4zmAhc9~0EyK9kVIDJ58f~QsY$Bzk2>lD8PIWkZKz_YbZHC)6L3a?fLJ5qz*13> z+)>a@<;{;uoqg$3N#B`_UOgkjKluVuM=Q3*Rv!;aPLaOTk)e6mnq`Hek*Xm%q;w{0 zm>v_s0KS_9yg%z|svJe=s$bsKy1EJ+WS}2AvyV`+2+OeHW<=EZF#i_S zHguPH>_+>e`ovUbyhBwwYb-`p@*IbDyws8rm-HfBw;X7&ze=pFo-3Cfi;12t%c8dW z=A?bW>?tH_l<#up)>l%VNJ%X2P|o_>&fu|J*`5qZ#aba(CD6JA%QtKY+nDdP`wV206CU>y@q#%6hhKT837j%|9o>8N{*|)8vT4f={&zNw8wQ zDk%^?xTM94lBadGeSa-o_Qgy|8PSR+-aJ{?XcoY++(u3=Z8MZ_q$ z_R4_$h_?oAGF!ZOKUU%*=RVX@TqvMQlL);<8q^&8kgCoaL~_dY?Iv_=x{TJbA1=Bn zRLosyr)-@CWMr%kB0Ao!h-c+8MqqQnb7eaM;$czfVBPt@E~9^fq@OZ z!X?dTT;UL$;_z5pYk)E1D?hYpoxTnKuKV~rumzdx#dTbk*r=;OeAN9C_=`f;rK-5E zd+lAiBvILd@Dph9o!l?6Y0;2N-oYhjT8CoibF^nDG36DHJE8fCt*$$zjH z)*TueGG2K1h;cCh)B^`! zFgyFpb{#97o=DWbBs=UXvO+NpC!@)er^0z%id7T6%A~Xs_V-)=RgUTXsXEj_!BhWDPwmV*kJ5sI2E>#+ zi8ppCP`HK%ii;K-AbsM>mhIk{xUD4zS#T^gz{VKsi4~y6EI79Ij%LT3h1l>3dHTN1 zf9i|#^+!<;)0b22ZB??co0Oj64=d|Hv6$KH%+KDlfFY+xW^Pyow-Dx9SBv>NE@zbT zoH$OPF7xG_gfWrfZIpoz6rUFUM48|G_JQ#rlW?j#KrjV`k_3l$hiYcgZXz>;eXu^! z7;!$??DbI|l|NhBF}C5r+oEeOF98O#}HIiY_#is`XXPB5MlB5M#T>kZ+4kR={iuWzuglr284(p#a9&WJu zMqMVjc=KvReool}jkcr9a&$0a53Tdly1nkO^LQjl!XV(3;#B3Y-TCCB z^agm6PtH~9bOim0h^v8I;m9*G`{;ToiyL|QQ6=9;Xq+@bsMrH2(ZN0vqoc-d`7x!m zGaEVri2zd%d+iHdH$8ElO>foQ+opO-?>4Nt;2dGt?UIClC>Z41+J?+C}rm zr3Wbvd+TpEyX|hVB=NE^2&XsmqMz$?WURV+0>v*-vb)*YhG<~<6c9y3*0wk@Q-5od z8k5ZB+DhB(NuZ;0+O4+LV4`KwZKsp&Cw9IH51$`l(z=aJYa8#q`p@ECAGVD>wn{rG zDyG*8Z+*R1dtd448QXic_U{p%`6S)$@ZY~Z3tdv*-gI({O8MsE`uBKj;TO&OPj83* zI8^AITX^*nQZ4<^bi2sKWk(QOhoIt*&R4+&-qrcIn< zC@01g(`F~rj*V;~L87Q-`~K1Et5x*#RObdV1Bla-3i^K2}akL(Q_kjv0T1<>KJ`}Z&gJGHx%`WkB=82J-JImzqDa-kj>G5g-Ou&h|&)H z6R@KD@k0B6T)Ocjj39|y`*?*j@}dc&WK!+IUmmILRMq8qp`n^~%=POChirQJ7mp6% z67fK7!{uZC(AH?fT_}fHzh`x8nMY$nN`S5Ls{V64qBq@XVL%( z>MRI(d)Kuq?NXl;f9`5&u4j{Eo6~94Ki5hY)v;sE&_x4Wkk0U4@>k~$SlYYa4Fx|E)xac##fdCLJE$9HO;=BzwM+<+ zp$GI3;;ZPHwB^tD?kehIcF}g;PfPRt^9`(knj*Pty{XC#&9(zjXtdYp;_C?vN`E?; zY^ZJZ~}Ct`oblK1_IKt3T%^ zKUaRfo|u=(I#H34devH0m2+!S3-#ty+IU?3bP`#%b(b7XQ4z}+qd|kH zd-Rt-zL|4ujTs`>hg7^oSSbThbMjq|T1$NmZ0tbIq?9}pckt%Tmr{+90Q6KmMJ_L& zT0#O4)QSpJx6YB#E3{xMY`*Xq3~TJHttY!}HC^(7Ik3tDHZJH3tjkjncMt%Vv~w(s z@ipbo3lB74`iVqU5$*yp3uWvJuBwpNxqz${NyWmiAgCSr(iBBRXAYN(VB-oj19EhY zc`3oI(93X*l0h|e#0Y&-{6!9r#1*QYWp7Qal1KrRl$0C*FI81l^T^p1ET5|7bFDg2 zldMrBXsH8&E_Wnb7E zN_3qvGZni{%T61BPzbEn{MJU#gx^X6exC}z-yvKr*!y=e2SC#+u%Mt|+RJd{E6tpS zjTq6VJc4Wlk(e^H0+{H()w{B?vL)OlplSmJ0-M%tDm!DN_T=$nYvW)Bs^x)|$=Bk- zNg12NuR^_ud3RS?4bYP9ThC!Rz%w#`MLsBAQSZb3h!#ppN|Kh2B52QTKoe0PJt*nI z{?G+wK`e2Hsif=gf+mQui5V9TecbF%jsDo+D-~5%`}oX;KNhKOLtI@}SX5#9+vH%) zP27dN+B2(tI{J)z%fwu(C1TqUr5tlthBe&{sS+{u&F z#utm7kQ7Tng?dYhK^g1g`ub)y^WN^#7IsW`K zOFCHzDdwVp(NO6;D#3iqMdectYEfYa1}3Zxd@=yM=R{NLlkL}aLjFXRkY*cM_yNpo)GVfDUb6xtD2r4v* zBAXUHU|=@|1Sa>c z_>n1s1PeF6%MS=hDWXZ1L$O ztY{)O7e@xkm>Wu`%U-58mbL%=>lX?@P48=zT@Z$n?I=-t{WLUs?WiUYPW+|7L|vJ> zY`kp^Wh+zdl=4P)OiSF@?dx1|1|p3U8^`>E-dyUkM7a-%EBxC%?JPTG=T23_;rjoh z1=vaE(7!szi)8#zR@{SmB+o(_O~tn}`=e*}u`#`6(zYQuKWf0%coxtHEOl&`kvhD? z{0lR;&C;4d*OEYN4lx1uVKk=a_@b8K5qp=K9FIH|9bjK`a?Po1Zun`DH)3Kmxnksg9(*uWfh{_b=n#S~?lW^n-)#t$xO__DDnwdp_vp356!f-`lT?)QC$X(i?Cj#; z#y^FX%R9zGBHGuk?K^32SXg)TDiT`-=uG*-0evDYY)3EM{$7&H$(jJrP*Z=nab3_4 z?^a7qva*C%d-8FG&RAEY^sz&Sx{*hgNEM@bY;U$^TGOcKiZ`RjM||x)>saMEP7L#M z(~W-BWBZ%izp;zM$9gem_&j&C;?=ohL!QLZw%*I zTAy%niJ^eDvILiw7_pljxOpU|ge@cFEocWT+|BslXdRt^!3R#aa&~s+#~H6>gJ2Pa zqQ{kY%nwhHYUI!%hQ*9+tqp$EiEbB0{vPn74_57#>d6IVexadhqeG{4Yw5RT4<#sO z6_E+B)GSx8erE1Ht;6iuZ5!Iy*dUf^kJgL&`IGHY6PF>Z5-wIhr;anZv@fB2l?aKb zsO839qmF9s4(~^tNb7$B{rucG&5}_gD9s>9CB>v>LjOds;YnJ3g06AcGlmU?ql$2!b z0zKvE`r6f63}9@*wIF@?lpa=X!=gWTs~I=>Z~tLOysu_!AO1D=)4fd1qtWN*^lRHI zwJOx@V`!}jY7gUi^BQSs#THJFtuWX}Rt#T_$nR&F5tMO7-@b7$Fn@LSlbyc|E)1jv zLGaC;?Wv)PDMQ#P(RI?A3bcpdBv{?`%EeP&-TV7)Gudx+ef2*{qeIJYSLF26yQ6K> zTHS^~Z}+sqo&@GV=bhX$f)(WP z)Tm>^P>dK!RQ9kIx<-^s@{N(mr&lw29Tg42L5d-+yUm*gH zrSuI|-ny3BONa{|fE5U&cYL^UKN(9W28tW&>OW& z6O}|)ArK7c2^PQ}W5#skvhaTW1L=`+?%t%Y)UkX7?*|X2$k0ZZ*WPZfm~G1Z1!rsj zO`E?-8qj(>NG6hmSC~?f5}^p3l5I?cKMY#%?m?ij2&sZ&&aQCR$I5K6wYWE*kEQk= zA{b|cKGhBb67*Pemgr>8y|OSc@N8G{JZ0L)290N#c2QH?OGPN2DRfm(9%8nZAU>h$ zPDU-%XfHwlE^5$&`}a=U1GK61|8SWcd+;Q+j}J|4$8lB&D*A1ktLubM#t&1 zJcMtMz$PBSILCUb3K6P)hQr3YR39E*w`Hg^8oBv0J%U{=qw)s+u7yYd4pDSx>fZsPekapk-2w6$x8U|;hR6px`Oz#YnOH&|LKAO^8JXCv=&(1HdmVA24@ugDXo z(S5+hE0;K41h48@oUG&je$mRdfN3azyxYz24UT|4-yGMkpUh*g`umrd;^S7D2AM0* zZMC3wqqa7`QSa-7^)ZLkfdGkk&}wFII`<7lGmp}!CReeKTFltkfS&{CWDNG<~feTe;8T=ujd9Mi)z{xA#utBNG`1wh7%r{UNErXlk<71stk|JZ zf`EE)JAro*4!Gy(l(4fsu%?T`C#Qfr9@ypqA<4jRj}PydV{GikRZ9s*&3WSbb!m{K z8UabO+0=FMvuN-Pek)#xW7SCrtG{O$bQM=66>hKM1_~_rZXwpJO#JV?OdZ@6L#g*A ze~xQearflJlJrI{pIyXo2bW0dNa_unyVXCMQ5~c_z54!mU(>zb-VN|BfN-c~UkI}qMx{RmdA2^$Vq z&;2N~whL10EMCI_dhg#a!Fy03v^G@`<( zi1rAEFV*Lt_jlas>wqQP2^$HYXK(x*0~Gud11-9jd&&$F{P3_O5-O*zt}fz!US83c zFP+<89o2j%pD%&bOIkGd%Vp^e$HEYxDdEj`deOoMpqNUPjz(>_VX)#U<2~r&qMlP0!7}*j{H&q-*=e4KS+qeE4(Ys;g**IGO@7dPi?i3UzGGZ=*JE0NlzAez~0ArvGIT`RWq=hyU*ia`16=bxQ$k7E^xIX&f|T)rJ0BHD zk{I_mg_so26;@oIY&Ul`caure?ESE}F0=@Ku?tLhFPmlT z(~6fEF=^j9{OQrxHgD;-_&F0M0V2h+&4x*Pu>9A#)~#Ai`jk!m6SQGtAT_iMyahA4 zkA1ePs!CFMxWhH6TX;ree{SFzHIh77_E&eTFGGhaP?bov4XY}F&prE(qzYsfVLr;< z1TcaW*9ee`J7Z?pHW)Qm2I6huWE@U@&Eh9E9vb{%z&+nh6&kT)ey(cBp%t zeweYPqz037%NZ7f#n1ycf-6#j>9|>q` zKt+K--9Ek5YS(K~@piZv6Ckli73?kS&QAzS27qXOO@X&)&WzKpSrefli|9k-eKZd7FPJaF3OGljuc`SLuP5-rd70kIrFw%AfY$x z827;Tlh09BI5qhuY~W7UhcO+Bm|u`wi?ZiZ&_SwVtNN;qWj$Qi>yIu zWqZichxUk@{oz(Sj$PJ7`S0HcD%(Ex>OWyZXu5y8;-0ud#ffqElr~H`Xs;dE?%1%Y zL;RI)j>MchnLWsaD|3a;i_Nu3j8nMV+lh;VlBs89v~o1?293?JrSpj) zotFQUGg1ILDl~^b->s5HpDt`FjbP_YU&eqJ z@=3$(DoWv*O}?TPp#{ix0zyf|x5#B}^i?Cn)c$cwpO4OLH8=1rG<5S5y{T-@bRNqU zAq8B&KaUZj%d|^)YsoVhU;D=<_3`>D9q`HdduI*q*a38_p7Gg|wQvf!dtk1zw+EeG zr*SjK_uFQdE+Kmo*2c!OhLKRZ;p>wj#FP~K-aJmnvwXFDZ}i60k{sACtEmn%MxTi; z**vbrG|0ksAL+g4H9HZt%@f!YBA1^2$2rOh{s(^&+{6co7K5km0YFj17%h%`#WW;J zk;$xiIA9^0`AU+)38W^%%?RJ|Jro*_i+w^>!4X8iB?d6cStv*-MAe1^WRe=_7;pHzv58$7>vse-Hs}zV*rKmrd&htg7ULv*r>638@Cj(KRyiz0~f^PCKlxk_%1i zQ>alfVKNU=EPH%Hk1230}g?pGnFH?RfgK(kI^HX1wxwgr04d$4o>ZXno}&-#5V z+swR#i5%C>Y}mZY?fvms2B;n2xvkJVp16Fb{W|g|NMT^D&0n<+Gr|;DB)Y|xUAm-B zSHLxP)YKuhT}3>z^x#!NaFuhtzD3W1!a@4aUZ!K#;`zj-q~P7m>Z868F#i!0J1uflo^N{&AJW+Thj#3uv&s8a2SD|!1p{1sWgmg$VJx^W zzoaPBf}yu4vTIjXYw>-+59FADULZkxBKyg&r-_xc)8~oKas%eeOldWZffO)pgS2jlzaDfK2J#B`1-My?()3v zG9$|0zZJ6oalHcEpaID0%R>bUtfA>x4VQ75xPQW6c zw+>4w+XYwwlWfv3@^YK=sfJ_s$)e!kWM}1lDG7Hq(rDje22zQ>J>l&!)N7PDA02RX zWebi}L=$R-GsBGibRuqDxMDH8ri)kjsDO$qG?7-nzr05F1i~2fCLudDRYejGZ~>Mf zUe{W+2Q+({<$wvk2=vC!@ znb@sc8cVkUldH&L2g7K{vz7cHu5Xl@)PD)8TlnfqT%XiDAiI0kweZ-wCaXcCpwJT? z$7XKYI&__rQ{S|?78a>RQ{Ii7aC&G%u!wS%Cm?xA7ER?iU`;yi4uycd#Cg`@Fz0O zZ+-W@TmvCpt2UG@|LxhcJofpB>5eLZnnV|?zSzXQigHdx)Z)#0@rVQ>XEnsE%^jb# z-6rex$16fZy?_5+xG5X6cMhvVU|J|cPtGnr@h+Lmg=h+RbRoN?g1EY2Hwt!555l0Fv|$(YKE7fX%0?wI&!XY?jck)WmV2Y>xyG?C;W@H|MV>rNIKbd8PUi_F|J zDxrCqKM?`rE^4^)&_L%;fu&a&#uXM|HgA;nT<>vh&Ghe1m=|-AC51@{h_UDK$X{nx zbRW*0LLv~;H$?842jeL~JW3PEIJ#R`Q>yGSfbF$yV8I0RaPB;A;H&usjvmL1j{(pk zPH;dCnfm%{bnA{Co6;sS!Nu^?$gRGC0e2r)9Zl*q_t!;)oJT%8lM0kQzrj*u&~MvgeAmp=kqa2~M*Gyw7mTc_dd_2(Ev?`Y8ci-!8vDTRjuPpima89%V)dZ($&=n!S8#<)l$(2EYZ1BoZmVxyx7M$)9h8 zy|NY`2^(+G?X7_(jVG7(J>Trc7q#R7U_FC`7GHM!F!$S5Jwi60ekk`^GmYjK53mxwEf2tfT6tCMzaL6MSFQ5#>ba6aIs z^`yAuW1n62Bkx1>z(M_h=;uqMU`ReT1*z`03L=RJ<==bl+BLg-*E|o@Js<0cR0gP* zs>yrC{em(^%oz0BX{!E>nwHhr9TOJ%J{d8^`Gj`tW8v1u#VS3{%pGGJw1Z{?h__kZ zr=OL|2KeZkLJEAW&J}Tl*#P(^9`B*pVYqxGbVjUXi~iLUHE1x@o214DPt6(@puGLp zE1j9yTKw54l(S|xCYgnTP>4d@c^VOhpZ71&Y4b^P;UW#3p(z}H1F_MOV0%`oQ5|WRvY$_4<{55O0}~E;CxM`DyQm6 zzWWYY7{Y%D;$B-O?W6T7_Bs`C66%3`io&;_6F&`^FeJhsQ4sR9#fxX9GRe9VLeB<3 zRn!B4Wh1Ez!Ad*w$I94^0n%+K=9#i#V`_{d3E_-HNL6p*<5{Vx61)F-QD#MSTwK+ekY(I| z+%ncs-WrWA#m67(bs{ir7AQ1nvZAu01);By3}{XtmJ$TB-7ABR2aVs2+%YlXa{cJm z?bOQXXVj!+N77M+%=Hp;1%BZo$s)2LdVg9=y%Xt zy?PKrSkPG2iQ$~WU>s$gj(eu-&C+c+;)(^0q*X|#H=(nYS{IKdfyKjH%P_6;>3&{e zzGOG>0gJPsHOEQfp>!z06XJC@RvDq0$sd-XfWzM_p|OwOOT-_)C@u2+ngwj}cGDYVw?XmYf?9rJ%yK4@X~ zJ1B6{Uo_E&zVgq!b=Se`MvR+r{CIKItzEw(i!#PO9`hPNgG+^C)KXz200#xiuE(?0 zmTLjG%6MW7RkZ5H4&S^{qwTvK+$%l#mF zZ*^KCRDB*85}p|H2x5-!4euw?5(XtqL66A5qf1l?02)+G`%TMdbm;8cdGvv>7B^Z? zy5fx8&9>VAM``BIW+dUHjEl5cMTgUVnQoeQSB<1DKIwM`cF;1z&c%$XjJI!}UK(CL zU)5Ac6BG#yTK46K9Fplk35AhC<9egB#Z52fqGgEeJX5Jlr*r+5we|TIm)3UxD2TT04_!RO_BXgQlmq zgpxgHd+joA0?B{@*#uQw+Is}>5W+RYA<0@2yd2)o@Y9J8A8a#CWooL1Q+ld+#>8nLNXB@o;Tz58LxZh{`xDv1tHT zPZ;Su$#?YS>(}jG&v{cfFXYH7g23=Dlive8R9_@=92`TfAMCOE*ovrELEJ&WC+$0Q z+_cunNnnbOGO>k5i8n$znKF>8H5x6MlFp~1DOT+iM@+iF2B?ROE1C1xP!LweZ8aNm zE5TgN4$~jyZ^+NlKrm|h7Oy8F&jn3UQ7hl%=x8OP>z6ML%+1vhn2~;g@F4L-XNuPq z?Jf=&sy~AO0;E%oh%pouK143-h9Js%SeP=NKffO}pPo%1TS<6X^KQ)S#MY=0;2Jm_ zwBEd}+&*5C@L_AYy4q392CrmC?IuyAP1CV};KIYfr=ld=MfnaA262T8PVL}ZfOq7y z-AgB?)u)CMrk`V7HKh?r#02`u3=MQ~I|242&!xC{+Nf_}cGJ8YkdVzZ6T#A$UqLS- z^J4gujQH7wXG|(l!?}>9VJ_R4z$IRC2%DCio*2`lLx3zvE-cNx>xCym&I2Pcr|lllP93>LxA8$vyOVO zKCQT@LHJRbE}WNG|LO~6RE8(>Hz92a4z*viMxUMy=Aeu$vpg_65FA}RYESqi8cu=(g?K=ToF=D5P;X$#Kv9BrFRKyF|c63O(hf zpQ+G#j2O|LulMK4l3K~@kBEtBh4Q0uvu5sm7Zk&q2hqj1wI`*L9P#%67B;s(Q~2$D z{)cIn2U3eLB{A3e*sn^ix7m4<=eVDhZq@EyG{?EPb@(4Q;5yEfo4UGMEWDz5iar6$`PQ&Y@|HxbQa+& zgv)l0i&v}|0ByF87USy1GK4?6lrpl6u@p#NG&s3v_T%@Iqm-f777qd9P8n`Li3dwG;odtZSNmR;UjS`S2f_Y*L=g*@ z;|^plx%4qH>*lNcwmi|}YfDTYow;O4aN7-fLBz<3^XK=oxQ7lLP&ARh;qOcL;uu+xqEbyoM=m5hv7u&NoBdQF9Iag zqXBKlExNP)$aANIDYne&{r5YNv7yy;7CE*Lrac^mK(^kA*RNg;&8acR3gY4aD%|lh z0^y7%+A$bE<^ZSVNPi>`D=Dl0%B3;E_MU0YI!W<-Mjrzw(@$Pjm(|G;^y@- zEp5uqMBvL-3kTrM;(19nD*1xD@Sl+>EK}b^*a;ZTcJ%(s_}INLu9^x%y~4$sr0>8T zAvCAd$08tIv`86%TEoJ!3 zqASAVE*76xuT&|BRGHSxM@(VT;0-3p2-wN7CUYl<;gs3x_+D`3B)@8xYH8AM7sSbj z^_3^I%}@mPjDh@Vezv9Goh91;Bn`P+y%QHZcdk4gA_68sP9BNOhJ|7%Op^KlSPPWN zV%(OPE(Ei5EoiRjtGRIO{>+lt%JELHEhL$xHhGo#*BP~vI2>Uxz(5l?GG!!Lz7F%y zlQthET1LhjL3+=>x}sg#J9TCPGW8sixGgh0;C_Rfj7B0L#A=vv_25emQM>j+91)Wt z@_BMyAqo6;rW9s;#8ln^`y8GD4U0@^p!t8%ekTt1dt@-c5O`0?hGHKT zBM?QtQ$r;sF>}MWx_L)HlJ^Cs3SffGTBhsdD$5Y6MZo_+T z)06x4I|q3_=?BURzQ3ItDJl5{1$lO`*sLhjGur^>UWx|mzAyGKYPENY*oI>k^C;4G z$C(TWZ0+@7WX|UL)NVJnRSYiv6j|&VSaXv;g@g(YsOB6{k{!;eCXhMuu3ObVp2$E1 z^8)q@(i!1`L;*}jQ$u!vSy{mP#K~ZU@*Ut?Ws*0o1RA_a6cspsdU`NxQf3fv6zdjR}QwgwFkv{0y_*H#(jkAGDZZSm;?w>S0a~K z_BNhf;b#XlBv(8Qg+z5jth@!0g>|#t_=Z0wrcYKmp#krC#{go;tK5Ju*)-E;AMu&M z#Vq{l@Rivjuj4m!nhU2wPz36@Q|-SS!j}S?iAn?zr+euG8LaC+)fkSIQhdG3Cxlph z$?kVV<$(@tH+4n6PXCd?bVw36K&W~mc_YFFz`b0~Kfymlknjn9BDE*DtK3nzTVx=n z^jJvT30DOGdbVdZomD;BHK|j8W5CD+7?F#C1L~7w=Cv{kL(v2A457?nWbz;y>&XlbH3ux}{MId!Bv-)4MJ_z|8Bve)jK znyok>hEd6wn3*ZDx@BWy5QZ^TUM24q9ftTMIPCoc0^DnBU53rM$t_~i?dXvsdttfg z)bcO7)(oU{llUjBNPsK#6&TMmvAXS%nI06N8^)JLnM5c#cjecwH=j31^rI@eJxe|P*ltnAn584Tt^CQX` zif8g!>a!4NGYe>l&fR^^GeT3DY_2_YXt$@!IO~kQ*8Qm5&bUM&ki`lLKO?4RNGU=j zm5*$`f+&)%p`X|68I@^)E%{ZCWQa%L^w1fTY&d&T3gmgCYMRVFkmTDnZSTVN*m{A$ z5SxopLPj08-pePsKj74yK{(In3V8k7@e*x{bgc_K=NYk~YN zVC&f``$E7pMWTd{UbS8Al{tg3 zXE7QmyqmPzjCB;KUTQ(oV5T{#&zi?FX$EeTT6lx0kpmT10n%|m9oVI|;?61RX;vOX z^_~@Nz0H3PtEd{+P9u8ad(>Uu2~X^X>UCp1g}bIhh$jkN=g(m`Vr`B$+a3SUUX$~3 zrLy)4S3+$tj>mGA7ftKG>epv>%|Zex7;Xrlp+nSv~$GddPheSUxJCrv(@Gw zo5!N7u9Gnkl5!&?eO>m;m!1-z#t~#~9O;b4ZvLI^G9pzi;Wafer(;AF*y`Ow;@FO7e}gH++Gi+*=(k4_wGEpH8~Vk zZjGZAv6>H&*nN%pmlS|SyiYC%NS2O#+9XD#v&5)aQ`gvktcj!g?&q}=%p2_>$gsJo z$77Y}4xjpE#?Aeei-Nvs%zR~bqmsgqfD}K5B!~=pSvQ;6!_=-AlK{V{KdFgnaQkCnb6Bpv;a z2vIQTSiWuYX49DxEe=lfxCLThp_h*6F`L<$1V=4%yby}W4bp`I?UA^(m;|_91(V%( zs@hBS-muf*p45=Qbt|pK)e}xVpT2fLhXLu@R;aJe4cNY*1?uI~wi^@ZJ!6;@MJ;88 zlGb}y6$g?;ttY9az|o+AwVHEc;DH^vpO%+W7^Po0_a=}|!4;!fTKI2`h|Ewd5LB`2T_g-4VWDL2vVN*=cUZkYe zNHR<+fY5`$alyR6@9k}m3Z<17%Vp>Ci;Gk2jSiN+;E7GG$FhDT z8FiSklHPn~Y4Z`Z6!e*>hh$Yy(X6b%NF53JJ!$H@=e`GkSKQ0HV<0MLnoD#Qw2^ z%R#nNO6{R@&2zGxAK>=j&+u0K!??ka?De(Q~iD)}+y^=b%1Zc{Q#AH}+1dbNo@N-rdlT2FHb-YCSJ| zf7*NZ-;V9jfQ4sYfM3@#6UY0bY7zcn3!jDYqq5}Wv&c(iNMJAegQLV)d) zJ)}BjG$kdUM%*{(;HUbl*HjYpI4m2=unBJOB-A`pcg`8TshX6V7n^=_QU=tkU~t=( zWF0ivZXolV-fZ6KgNEBut8M!7YKM93GL)k3Rz~r0aSr(pnkfC5+2ItIA$P)otaUS7 zPoa-|^`2fAm``S%S}nwd3oyw6|M(SN_J0G(saYtem$t1xJ#sdane(|)l{*>Pc#C;T z2PnjoF8K0y9}4#bC}LI{{Y5v;rg|oSP*;l1{Oa#D9HTUaHyqyIJFz(EuEAQ;qrYIS z14RR^vw7Pj@A^)yEYLGUm zn8vjkJoS-r>%F@&u1+&)i^NV0yQvv_HpZw0N%}kyU%js6qDLA|r;DHV*{hWRw_qCo zn(*v88IEPZnmat_r1NRRUs>=A?jf^SyrRw8AeF&SS>0GrDMxF+92(6Tr)p7B&5qT)3ALxzJ z41GJhzAn{e2KsgrYK}o+p3}lSE0HA3NeO-asPng)T4MNsVVa=sl&uZDbz)!e7*^qo6hD3c%V8**olwCpfS8v1Ra zuV^BnB3cotX=~L!ZQ*992-m?EcXoX3(of0C-|Wwp+>7(CS642(O#%oSJBfH`oxB(Y z{l~*ZhDd}HjmEjkW;k>?#z4w3&G%`txNqOn-ATmUw~vMabQHVmWR?=FVOAG2{#LLP zo?ZtMSsRv17@ju08DO}{UOsS6W1hbY4e}&VQ*5MKHfg1GmH$P z9df1pas9H`Y0=zyZ(P1@R8sQD(Wwuncye#I*{e>xY8j)~X1{HKs$=ZlX*08zkI>xP zKRzW+b46>Ly>XgJ9{MIR_1m|d(x7;8vHB@z*FW(UBZF>gS-!5>6kAa_!&Ap8bzDVo zg>%l<3rikR{5f7T@8+JA5D~p2EV%_4RD4n@yZXFE5PiD*;#JOieSAU2CHI`WQ=SMf z`fAQq_)6sDq7G;D1?H{>5!JkE7-gKMRi(JvUdl%X+Z+(ojcu)a^b{AsEI0EjEiJdYh zX+Yp~)*C9Q8HH-C+56mfr+r3A<}51M( zj@s_GZ{I!|W>%g^V?-tn7v|2n1N7iSL4pMdNIFz#`#G9zJzJ#)@CP4?=C?*Fp1P(Z zr}t_td=uE}4stE|H8fCqy~onCZLfIe#7cjJKrSlU{Ib_?{^qU!Br(wE*6%kfWfBC- znKEx5kL3KC*391GA#sj+kiS8LBX$I;H%z7PdAtX8lPQD=`st^k@qjXtt)>j{C)Knl zgb`t55&#W69mwcz8(q`IH1s_%Sen$@UnoQJJs_-L)L0|Npgvc^A#;g&2vsv*|Nj~_p1g3bnUtAB|N`O+y$;s(z%G(zyd-l~@ z*P4FTs|~+Z&KvH(G48e$k-P#vVVLbBx(~-q)4MNS&w7(gjNDvb90*CygZ!sr2|QOJ z({7m7G(8|>(cqwx{K?l;#`6^|3?iVXco!b$`$7h(o89IU2( zyF&xU4t`IO3glX&b=4J$fE374LgP{qfwai%HwH$E^R%qndgp-O-CyU&@Siw48Dyu6 zYMpcb$^iq+(Ex^;{Dl-qLcl;EkGZKcsih2HfNHl|zI=~Z*XgdxqM9E_V}9TB12?rt z%fKYZ)QeMku%jc&t}^eAsv>>WDrdVghBr;W-u%-CFo8>eN~~1i+NdBMwN9Pp1b!V5 z*i@!Pa*TM4E!>w@h+ixu`@(f}Q<{4{l^6LkV1|@oa)-Zb&HB=+>27L($Qz5%p|J)} z&)ejusE1gU`snAGxXa29pQCJgW|G|NV&k1|bi6`@gBBt;mq3^+4c7D#*+}NeY4SM8 zD?V<&ZT#S%W{@o+s0PKGTj7`JQje+tx(r?+51-|N%Z7adSVf9#js=Qau+vJ@O{_n; zfp=?uccLl!`pT>{#94NNU|e!J3u&}F?&NAq3VGOwT>NU7dAviAeA0bP7B`d zJvTqw?(~_t1GvQPQ#SAj1qq_Wg7b>3?jQH&EDCw9y#`dO7@&2boMF*UW=)>6!ASB$ z5H$R!qI2`nGM_-*uLup^xD)lgQa7ijgdCm47-I zJnne8B(~$gj)y=#Rs+dTEVe9?>HY%XOe7>}t)R{}} z$MjYDJAU}m8{#lp;&Q30(UMEE&YQ_yuwdmoM4zx$JcF#y{{&5sTyVaC%8u;6X;*(| zH)NI2Pqj#SIQ-)h&Jc)a+^k0DCoE31zpTKTXvk8A35QC4Y~y&k4CN)I46?*42fl+# z1`eIoCrA>fSW4X**8?41(Ai7bHei#htmWh5&i2-s8t>|GHXk5?s%KdH21WUYb<0jb z5KBTBN4m&fQ&M)oNM@DUUApz6JO;6$O3KKoE>)O7+i^-0By=`aWtLG>-luf4{C5!) zP^NOhGMQ;7C)6OFEO;zAjxo0)_Gfs{Ub1uOVmD58ZF=N{L6;7?>n&%EOL_0m@1GYm zDWpS-KtmjU$UgVoZGQYTejph#j6Qbhmk~d-yDdd8GjeGQ=vVX4>H#j}PmKy+rZMw* zBi;6|W}*AwI*{q408h0~tB2GLSIl$Ywy*44wCk+bv9z{i-qZ-x4O6y&X#?KjPyUwuI| zTO6`PCH?Z7)$0481jG;;keen5X~N z_}=wpy#*`!R0X{aN-MMhTgOiPU`g$dAgiTskvGaG(3oF+9F^=Pn@1|u01L>7O8nYQ z{r9iRf2}(>NG1x6i9g(MUv4KVsqXFfApvpkJAJ;i0{?!bKTCFscL~Wc+K`ZtUgp(K z?q3eBC;XhWxT3GeziX6*Iw^g>8`b5=s?*;uj=8`4KYz|LF@H&uo!!t8crvW$^op-j zTQ(5G8x7>9+2%aM{5nOhC0-qYRtr|gm|yxcPU6Ifqg28*(C3tX~TF|39ld-Md;6cR_DNNBYH99*L7@-HrC?&bQB9TKc~~T2|K# zWENpdCp?rlHht|#0r$|b>Hqb?s(mCf0LXw~&G!jA1FSatXs?$hHbx4FF!<(u?tD_VjD=d^{ONRb=&)h+xa?=2nd0PhJ!d8PoCvDL3c;lhdPx|X!RIk}dbtcFDaX<> zFXq#X0fF~$`*&7p1fR*c2mbVnEw}Nspv7X1A?XwySH$(}^FEK+F;T&P>aLs|i{y_# zx<6u^1vuTwilczL-3#Y+P1dw0zMr40IAVLDRRhJnQ-*zToVn7A@5n_6e8bn#L){6# z{43`XGv0Z6;F~BZCz_fD<~TJ{VDB+lh5-^|Dmvdh-o?piY!l_?%@H*bIsm~Zp&m(g zjL+kL_q#lI$PTzrGr460euR(0Y+%PbjR4KN_>TOdx$fp7G~z1VpC75%hvXleP!Jqy z5IFkc#j!j`XuVxTdc(moQjfYW?M7(BdWn~oK61#uF*)o+N`K1O+b=81%hQkV?i?_f z;!U4~bB{*8dbz)P`0qKTqy4e@nZCTQ6SL2FL>4@-F1z&dt))6ZrV?szB!*1LHY|-N zvH&fk?ql1@o*tPB~vEt&040=-Id*mg8 zKZ*5~ECOhF7@xX$mqsUR$p>e!&C4_K$9qo=(VDN~f9uD(n{84w!6aD$UWlypD^Jci zUK~*1{!8hMFPK#Mk5SCGr*ENSz;LKeRpkA7Yrk*f=bvhBPXnpRs1_$GH552|dJ45#6w$OG~h`Zt5rw(k{6K%=If{b74&T%tBjVAYM zZL<9W6*QQvZdIgAI%0K z{4D94hv#BdnJZz{`wD8#EvZKWN(pj~nq z-Kh;K%rW~10#G^;jdmvZF_rTJ0!^+oHfN9V^a(Tnc6xy;3eP{xJ@nLWNx+a)4s+^g zH1&u=0b@Q>@g^f<$Codw2*8=OPvd9hb_s2u>I}af&-UAn+LQ*_w)!1{Asb?oIH`~Z zCIG=D->7AU4_*C6JEY()^`^-B=c>6-{t=)u5kZxno9TddtVGeekx9CHQw^P>V0s}H zPf}76v4Ka`F}y0z$h9gU$7vnZ)~eh)i}w`;6rlOXD?VlVbgx7IA5G^0)^q>%{Ujj~ zS(WUptV&!VC4`h&lB_5y<0>P{CQ8F9GbIg@WM(DGh$5v@cFQQCkddgK*LnT#=RWS^ zevZdw^!xrk-}7^x?{!wqIzEk5o8}zsY_EFaO4onS9`~gF4LNKGdCEKH!lHg9Q!9I8 zFB0D19*%1c^`S4bfE@ZKyGn zZ}jcDi&w7P$2T1ND}+Ny3Xd|~CPzj7s#RL6mCTADPVYc9}Up~UO< zU9y5i0mzYF$>sC*TTc;-v_vlmP!dzo_uxa(_W%j-b4UuJroq<*U*>L@R{Dw`6d8js ztzeaPS?;|7MTKYM?lZjhz2EyE79wF{p7kb80CE&)`N*XEn9ft+utfSIYna{CA8qPJ zWrFY`Gig+AGV&66UK-bOFK%WT4hxPHU_QhaD~Q^=e!we(@Z78_fARhMDgepsiowpA z+M@QrDqQoIS5oqs5D|^NeqVA-`SNZgE&&aeG@v(yB_$>2NHOInE{VTVuwd1CrfN|c zLVO?J8H-dKiPJsOg2!AxurEE4@WtJ-zon!PjlM)`o~qL1c_Ais`FNm96G^P%LG3e{ z9+xMcaa?(_D?Oe#6-aOjf7AHP9Tf0^`PPJSi>?r!RZLB zJDCwJ+qE0pXfyu=8WLGE(|?kl#-`s7=Lw8U-pk|nHmw2a5P(Ojt8N*WZh6J6P>K_m z#i^<~4wNUmzD1SC``nmAJh~!=%poO-Ergk>;eDhm;|OtbkM%A zKfF~r`9EbS9&NdC&mTA1OL{s5vzFCg?x>M*9{0-&xsq+XeIt+^`zg`r8aLJChM!zc z(K&5*UJ=M3;_F*lB7Ej*050~wjv6iRMm!N$_vjm>-`j#K%_o35Va*861>gIehi9kE zniYUprUZ~CaL7-PK|zW9TQd#Iluw@;Xl&4@Pg8!2SiF8b=lWfaiuUi{s;q=1V2pm) zI>J`Y0Iw#2@#Fd{RAlnB4(ZKTM9y)ZK6w6FN5=A``no^h6{6e<_y0%lc`emh_Fe(M zxPBwxy_lSlt>DI)>lpqWD9mhexYc?$IoK)#Z&r5$74Q9<^~|Ejr^t0g5O#V{W#JBz zuSAd6ozBD%H5hs zIQczLFPHGF!-E>5Au!BD?j^!i`R>+wJ?LEbrLll|;3?1WXuVmlp{Y3^X`0+nMkg2y zz+^D+dn1o<`EAGr$5sJ<33B2~7aZ1jv&@QhFH@8^hpPi^1iNOSFu9c6Jg;Z_Hyoq;^*<*@E!YZtVWDqtj%#45tiM`k6w{KTG(>>1p=@53QTE5P>~o3&)Y*+?Wp0!fhD z`yn?5gZ0S1MKwm;5b~VBAKB05gEq@7*5)>gAhbR*cDJY9pIYe0HX<~TH0tg&Fd|*(v^E^LG@;YtuBf%#jh`4~2nSK!SzK;zvzH#G5 z;FiS{Yo1B=QL%0C9&ikioeia;Ft8Lui*uvFc}dpVlS9-wk*{pqzC8lH8--|!?tUcj z;(3v@0Wt3^+JT}`k^lua<&^sBr0CE_Yd&2vbLMmFtZd#_@rjTvA(#*{TXN%~oRqFz z`F`X2t?)q+RCH9XftxyfI)tA6Keg4XSC3!4vRbKV(5ecs@!t78c}Eg2^zCf2eh1pU zut^pZB`+Ik2OVXvLBPi%Wey&gLq=q zIZu?^ji+n9yhID6(5cax^mTpP_{W@D+6DJsAn)Xa14E6Bx^NUQ153ZT-#v0#>^b0T zx;oJgit4_y(ie{iNT0Ya7}i3%uY>^-jmYM4w{|hfz|)W?+MRRGO| zKV7*}gk3o!;7Iq~VaJEdjlMZkhu9t9$Uo}yoaAf%kte^g9CPCN$OoZCWZ9h`g| z^jmc2oE|&kS1y&-w|(3;g=MuTmJfOKvGKzUM!{*fCIvYnd7Te1VRzNND<@-l-CwWx zKLSxxR|1pITE@_JPieZ4`!)B2PRIW(l2=m@*)>nN&j3T>J#p(%0KF4$vU7O(fbk>r zjjqMRFYI;H($oZn*uQsPU9sAx6y!l%s+M2dAe4uP?KkVPD$D#3ohLYZvKT{F1R;9E z@*~C;5&@*q#=}wvo;a-r(4vGT7F(fNrw^W7ey^y=ff`Xn&~Vhw--PUq!Kaj3&r4TS zRHOg~Bd3oeJFHhsa3TBlubK^k&n1FzWyMsC! zdZjZ0>!BRxX-(#Iq5~P(QVIP!Om+jFI|#S7>Bi92pE2OD z34Q!dSH!4vPQ)9Cwlz?~8;AH(=-Y%}Cr6kw#3GWdl3;<JEqT?!%i#a%n6%2 zd>IlBp%aNZMHBP2{*?9bVZ#IfPanf)r{KxndM@n5{F}DA`>(Qc*zxx2dGiXbf2*)g zK+GQmLP@wP<#tM3o($!P&ELK83Q-soa9{RkP~Cm=CRWT7$*)KmggQH(cvDGBo^4Fb z9UuvM1j>~U5eZ=3xV04&(23@qTlNXSAYM#{W-C@0upkd6QC6ICxKRc!;QbX=hsx*j z)0%HwoE)4e>V^Ft+s>%9skgv|+Y!U)zgW5WQb@@pKD~GW)~;J8A;^d&xsUN{Tfg%A zo@(&=A#Q?cu{Lof7AXAVJlDd;1;1`{~*9rh5^i0GG2tjbi$?Y%~qL|8HoY`FllFPlkq^uK8&GIXBrg6*33($N?Z? zE#t?-9>1JuNCWBzo@-DPbC=lysBfDzvKt~b4WH+@z7bbsE)%b1N z_2vI-0XU83)26An^%R2xiVhz57KTk(m%!hj{qfmR)}Am=5$Mrg_l{M(ts^P_<1H=k zKZ>I6Vfv(T-`60c*j<$H6bI?U9_U%e zEa8^y)Z_s4>RATenfGAiWn6*b^?#lD3gp#U^xd?%7!4KGa;zT?c}QE1K&AGX+Vl;eatl_D~2(qKvsWRsBb8pBuj6Xas(M4IAa99dwj z5@3fiwMCPy3dml3ns*=>L*N5GeZY#FbRkD%wG-`z#0z7yakR@?{_a6rt!sI+qb65% zqHE&}2+;t(&m_S0CCvYi{8?gmM1(1sr!E_Q$pl_%T0iuYK0zKuKm&Q#o~Bje3@Bz~ zB(I)1tAQxpP=$Pa9YYRRM0yL>KQoUayZ*1%hUxyQER31H`J)yACCA>oBGwZ}!H-`o zHT-W^Ea1RNFSHOcCKzeAkg#1eWBU`IiZO+YiL192YYjcik3qXO6HmI`^SIxtP@RO9 z#MFjmm0B0x05XB_vi$Q02G*r&LQ5q+fnha)h{|6_6NV((V<_TGD+=7defbCYW<=BlpeOQ{8}0F{jY@p&Z+kc6r`g z{RRS~fIzrZ85$|Pf`H-3yDmH#{JPb%mGi^3Q6Zrm8N~{@0yd-C>wR{8_bpfik{I@( z`Mop!Zx=QLl-1+4lb;bsT6Cj>JSfYs?LYddYj$qWv61#U%6hi-fmTXeu#xd)%a6&H zs0gF?3`Tks4LPO^gtxv6&V|p;V!o-J*qvBj{)pM48HHC|QZg;cQkxdm~Z`A_H?CPL$2*Uv-083*-a{ zW8{wE+4|b~^HU!#%8r?lR?*e!=g|||U0T~BmBQP!g}UF3g}M;&+AD4%Yv2xTvQ;($ zP5j*8o7>yUt5>gfF*1@E7;#B6-kn^+)!>V?h%@4+qCg~$gp~p50g9%YvTw9}4oe+& zo!V1_=Jb;KLx{WH&ohhN<<0>Ukl#!u|M9JD80$2MF30-&g~P(C&wU~HpUz#^oS#}= zrT%s;NfP3U1$z_~H?)V%!a^#9Y=;JRSp4~=NcWZZ7?$p6%IHTFteDe1lz-RHk?@#L zhL`M{!)M3_5S|##XOQg-1pq_#cG^1U+|G6Xg(hD53227S>%TOh(^fE^&~6ipJEUCT zA8yF{;pUd(>+drVeqkX59e4y%Ns%4{%z3Py*Y#;Ip$im&uN20^DvIRD2u2}7Qp7Ts z6hrY%dVY+*lCbp0t#5Yh)MGSJGLv0t0=uOSm(Ul)1)T(D`+AVvlU6iR5PY((O{PM6 ziusSs@TKFyllLbtcIP&dZHUUZ{2eP?>dp@=GfNSRg)GD&W3Xf;?uQ!(UMG_QA^VrH z&-3h}YQ+nX;6DkglGxeB5DZrwm|h~_0n@~?7POOJ0h%I{lfzG4?y+p?mXXI6I%eS& z!I8eh-#_wq8rt~iyoLSy^;4A~KSm3Y1Z$bPvE}~TZn*}~$wwcZYF!!2HHSQaBVk(m zz4ebXpw$QZ%@lhtfzz^9aIfWFgL=;Iux3MPM(8Sc;HVJ%d0#=BCQ1TFAj&6z;9*$@ zrOiml#Fjx|*N%XI+=tVJX)j4`uvDSCk6$p=17zmE7pLSJg|hN`8ilG9M9s!2N_xc*4NLA)GrJJAdfEr3Fcc54^Kz zsl-pn*N<4-EUs<|9xlc#@%-^{N5|T*B$Pbb(I^&K70PMZS#WApPS*wh{>zDL0W3Hr zi)I>6>URFrZR8)*V)yAc%#-zq&RJs06~{Va@c7I8k$)ke06t?hryy@4|ep;1zOQnr}KK~;x5(F5UYyG|%`T6Y-{G*wX=^W%yZTe`uZIi7ebQ<%aNNkd~0aRRs>Tbsmzjs@>XpyW`7BULJ$5z3vOG^i~)-bm= zKKRfaXAlXK6NhRk4KBz_%;i$2BWD(uwR6Mb5)b89yO(Yv=UfUIn2?Y_OLi{&k~E3?6Ir@2I=s~p z7ZWYwZDqY1gVWkLKjq=67TxXVwY$<2Z@d_85fO`wh^BsD@c5@y!C5QGJ(f6Xbg)om z`}#F$(nL~mfl{a1*o;|Mhud3}jc^Je!6WfXa6qKzMg04qiO!~v^fqEQM?}Qee9WUo zD4ao6mZ=(35tNjW9pht$?7rX7tR)#xoxlAZyrOXN&0k!j_)i2VuwQ2F+l<*7x5m_u zcaZ7uGFzXpinyd07aJR4?;qTtIeS=T4I4YDWnL1AEdV>SdG6cuJ&~j6(<^IeX>IM& zL^dPy^Vqiylrl^oj`r&-VIGnXDlu52B1WR(YPTkP_Bv_})>yKmqB9!}UtY3p((4{= zRAL7?;KK2FwFxd>E(W~jypSi`C0q5M4fW3Zz8%Igl6jn;kbR3|G13tSawhk=R;Nxa zAY1|8t>1gCT|2FEhxQ;kWOx?Wr>tAg(bcu^lE=^cPXG@YR1Ik^9WqKffAZ`A5Rc@= z*F!bcedN)1p1^_e4{k#?!bRooYQ*Gui>fP@3*1=QiamKgeBUyC;8<~4zg0D77aN9^ z%#KAyDoQ|iL3dr+^WFD5d~2dI;GpGn8|)i7M(=r5#T*BTRGyUerfeRgjr6!M2d4FZ zFJ^i?Dt0G#Sj40hjGTL`@DV-mTTG}!qqE8%CFMa31t)|+?aQF8 zZSdt}oPW~CU<0)k=Tm3+)tL`-xu*RXPIa@we6!K-WknhfaA`R zJ=dWl*4f5r|N8b#@yp4m%_mMXPoo9sK?Vq0vQM;CAh*)y$Se9TkF=_B>H5sU2)#6c z;scjh>Zpt8g>p!yX~Sh|%pF~jPs<(wHXu2^d+6@z&+d0LPC%yd+q<#tn>s6P1D}!U zE8dGmK(~QyaJQ-wR1B^uWZqXThzIv;v&ll378bR6+#A`+^@l%rpZf(@x({OE`7b-`s8u5G`#po7OTCT-67lS&u?YHpqM&B_E3gn zJ`0+<`A%_{UcG$ZyUd8odv?)T4U7Y&i_7W|AROKa7lXrhiX|^V@HM{r)YeDydxi{O zGk~|yH?P(lCBgI>o*_X)+86LT<+lS+pq?TalC{U;ro53}8M<2VLz0yv9YvrT>XEm-|P-t-=7DMdxOUYMl0R| zvdI?4J2z)LDey1Vbvd&B7lo(+B*lkHV{L3fj3QCEVnt-w(}T-Fk~})zc2G}65|EAz zd*QQmsN0eyGJ}R>O&DZ0w>2LJ`KuXrlZ}ih&N;PZ_x7exxPRz+;Y;Sv4|eP;l4ol zF8)2d@w`gr{26n-8j-Te@6TQQaPo^2-pf{eyTaTemH@_-^1p7JdBBTl7Ng#-5$_QcVZ@_1TfDbsQ<^$Tfk6qjr7(-Nn8u zFrolY@h$%sd&}LvfJZxQ*+vw@B8F#e49)5j58*<5NQTC$qH+l!FW#t#VZBbrCV%IMni-gCpw7mD-ZMPZJ8-d*k0 z_U6r>5x}1^KqEr>LZ7;Ls4=iEhz=c8?5AZD_m~;yv>K`046^Uz{P1Q^3DThws;F!q z)%Vb;DZRNcRs{`U&L{G?CFDSxSOMF`#Pve63zR6*G6$WrRxO61f#P=wHg@MMibf7Q zLPt6kd&eQ@GnrIDH%IN=3@jjAjs4h$O}T<335}~*90tRx?1KB<0CEu%5(>N70~&MV zFsRDZFJ$MPGeJF@D6Y6R`=S1%%SUOmqBOtCoF;0Ce_u~{p{{-_{!4r-L zE&dUFUK*k;(!>-D zm_kZ}(3LG+`P-1hB8gJ0<#U^i8TsvUZX~KI_K~u0vG2A@6x#4=|hI@vS7hke3H6G#lMM3!E9%~H6 zNJcd0%B{u&0PzTB8yCN3g%vM#!be!9(ZkQ`Qp0h6CxP+m(;mtIukk2D7P4#WC{AarA^h;e8GB!Pcdk z3^263v`@0!jKc&BhOX6&hBzwsGP5sDOu}NDN0(zln!4%k_fMQOC|kmv&~alD|`d!PE$dtf4s1AQq;NjYw-OsJ@@NhG74wWHlCiTc6LUmbvh$q+vejF zNw-Mf@bp93f$=&>5GC0~waeZ~6a2ws#|Cmwr-y6j%TJTqJ z_4dk7o~*dFi#5HM84Z8VCuJ z)c-x@V#$WyG)5Abl%2iz{dESOVL!%@CxRJ-(|oN1&JUDOAR?ul=%J|>Z2v- zj)6VGMpuUZ8+~9Y> z_;p`hf4mmHNOH!M6t%(w@K(!8+~sSo&29l$#>;Te_6*#N5VWiYRlV@Hui5332gmE| z3+&ZIQQj_kh98p{_W?TRFI*^w3Eg5q8!dErsDq`WK|%>+KO)}I1us$Tw#h|PXZYf9 zSkJjki0%X;h{6Kpaqg!@loC3t6r5_D8XE;WUP6M1IO8_%E*yTvEeh~oL@nQ$F>izU z=cfWNCMM=MZ2@rjp?Ph{q@%{M3*GwepU@9c7_x;Y&RLOto6&#LGP0^>@aZB`vzBeb zvyG30Djg0y_R(%<@n+*Q>ax; zGoEAMj@Xk2D=xSrs@w>TDNm^ugNJ^d;-@y_%vfdPemu z2vZ3N<9ZjHv!=UurR7mC7iZ@fkGZ{`pP{=7nC8jUbEidJ(8{2L2k%#30p7X|nM9)# z*w&aoE_q1|SFyG^yw*~oFoliZ`wKjwTqhJcxq^?$WcRCWSBjl#?%YlSs4x+b+b4Mo zM1Z8i)oC=$gwEXz;D$hWGZuUl9Qv0R&Luwu}cHpqM>v9*7|6PbkM_~kg$leYPgw; zR@6(vg2+Gytw&E}{Oi?9F=^5mbkZRKpRNAFOZ@>3%_sDKfOvh2rf;a8d@^n@%G zw>s~yHi;YEvZZ%I@^zGi0vuUWR~7*L(tnDsl7f35tWpA*5h|XtAOCddC5p_GL(rBa z1qMPUbPY4Ka+;yhVkVwz09d%8xj<9?;{=J$qbq2!)E^C zm>{`jXYp+SnAkIo-x@D@a0)r-v`I?H_KT)^Fh&wkSxpYtCDklwff6n-(Lpj~=&z}m z&6$>z8-|%D*Xq)SOyt@`#4m|;;+G2j<#f5a$XQIajTU|X;K!dI)w@mP&6{)k9$Emz zjttoQ;X4Y5cTn70jlq2@5#&vtp2_G;>F5r3BtXccTr{_RyuYLkkbdT`-aA8 za?(c8_pve)NRnqD8=( zw;a2k=+n4;rE+uA$_{gS@G0?`ge*x0UHJ{-9%(EbU?UR>vmQQ-3RUL1g1Fs|J9t;8 z5&nQ3C-W8yWD6I=oO&WtQ(K~}fSHxC(aDN4Q9<(A7hw6eZ))W<(y@0hZr3X(*W535 z7d-KaE5*e-0_(z4(dRY-^QKR@y)tV=W11XvHf8Hi6qgSGG?uhMWI}M|@HDdS z4-J6N^p3+kJ9*p!$jln?OB)9(zu5cmncZrVK`80|pc#DU;&9o2Xu_~(X#@Iuf7V6- z2B&q(;5fpW2?`yxiyC&i^t#u=o_<1&Q^i4d@4+&;6Sf5b$ET9aHDrT^M~>gTc~sw` ziKmUn=$pT8E%Rh*VXkW5{)r;Pr!#!Mn{mC4QO~uUMhYGC1m|RDA*c ziAc3x-(&dj4rq5sr@Mo|I@Z5VY~Ec1(oMn!FKGwpf*wq^7?y_xh0Qy(Dy-*y+V?}I zn@qU;MEew06>T}TJg6a8M?~FgU~qUJVw|TeG2VSAE_H!^|0#}&eRDhie=Pt`Zf+u4zfwWcps09oC_d9cRp4%ib1Q+op%H3$lFXF(KeKk$eB+n+&EFO zR(+l?K^vlK!SK%2i3Z;K)ub8f7Z#N^ny6{HLg&PqQi>t9KzIH#G$PJV2Yw4Xjb{O5 zjGeKgdF$hKXH=~@?5X3G?@4-3{HPfN4t`8H4?f(d!x4*2|I`JdBog$m;&s#~oejo6 zB>@eODt=caWQ`y=`v1!tf+KNO9#(l%ER1zZ2N@VFXqbZSv-<4)`cNhCTy$I?9EWBRC-A^?Y_H%8 z6VNOn?|Acju#W6{rc;$JhMFK|50C&vh39~y?wvfk2B5eyG6`i!?lEEn%D9;4A z>)Nu3jFVg{jD+0@KEY5swEt*=7S+Wx9uN?v=|o=)B+SdtC%W@*uVJ(Iw9o+1;ilDF zR6$)W&Yf&}e232S1DQZi2xmttKNues7Zc;F@4ZWU0CA}>w3x@4Hx16MV;+cp{}%_9 zgn;96Z%Ru)cI(0g3lxt}Ys!EuP9bo<7}fR@#hJjLH(FKJ5-75P0{=c{QO_TFGh%I5 zd&_a4rugsRm3u=sBXK=Dx4{}P<+P$f6H0O6>Go~g;w^GyWCi@m*rU9dHHdleUEaRq(2qcffPYDeE-iC%vfD}IMlqxsLQN(m_bF}ze1adr43oZ@;o)a zFlgGGTT8REZ~k9+P)Y4XSIDzHk-2;tur0`dcsa{Gm|Mi zIW#*9kfa|$!Ern^#2e#0aWf}X?t*mj3Ky~bAm1R7`+nlkrE)PZ4x|7o``(GT^fv$W zz9*`liythV6F(s?E-v=s=JCIOk{b+LuCE+3!r1s^m4p--zD8G zZ>hvz>grjxRFZ}j!4p^}Yiab3UOye%OQMW9UC88JcRJVo{r$u%6k24^rHxD9{gQ=|TtJ z6J$YtJUbt+Atb48++k99U>2x!371zfL`ZAN8X~agX8p$nPB( z{9YQNnah^#L}JapHMMC9PuuTzHY9ZW!GbFlBZcs9|7)oAs#QjBouMLsk!Z; zD8VkxfFaq%Viww!>xv-ahRUkK8@nl7O-N`XYz#_*DK<9WUsz1(za_G_jKOGdfiiq= zoqCR#sswhdtT5S>=+@or^3=w7fV{I2I=B=~vbVx8cM${42^H)gam59-M)0mN?#iUZTnxWmeDl zzqb}A^>#!V$>$xzx1jaj+Zq91*{f@VL_$cU)i>pk!CKAH0w2qEkwjV~u-&;-B=p7rpfUU)+1Ik>+zS0I(4*fi-qa4`QE^Q)Hj&VFfE|A$VEUtHJ0rjc&h2aF&ciQoGuSi@KNh5GE{V8=qe898AyDf3>B8`w)^^aC-2p!&CiP0 z9om?K443>brDeqO0|dQF#5s4Y&ipNVhf|J5to^Q_kmEePu-)H3h4q z0n=jbR{Z4)+}7OJBGI8GJqOC9lQySjOn8-lpAYsp*18wLCXQUI(JR6tdrPy72qWqu z1Y1K{Z?*P&3jHlfzwoT2&DB-EQEM@M(8@}_JN03%i+1^_YHpn#XS;msGb^_eFo3_5 zjWNz)bf@6W=Qh@^RqxkcWxK>Mjg7j+PdUD*>%f7#b=1qFkW@>x<-m!2YegwtxuYxv zX2maea<3hW+}tL=^+()cQ3HcQ=yCvaGT*FM@Luj*J3k-lkjNuJl+(X;HQrRGO^&@d z`NeF{4ooHt*fkNMu|V$@{cd_~Uv)k2E8aou18I5l zR}k@Iw?)%u(N!E8fb;zL-7Gfo-68ep)xh@Nu9)5`q-yGHu&OM$VY&9iSd2oLG}pax zXfZKY?y{!F?b(X(^l5v_`510JKa-e`XH^g>d@*QnxxYm;lcZ@~b@#;8pZ#%@|Miv6F5`y3_-Z<=Q%&;c?S1^W#>IW?TWcCW^{jpwi5FuV-ni|!P!`d(o>KPc^rr~P7@gUxBUdXiJcx)n3Z>BDO!+|Y^d-g?_ zBq{6{ohM`1j6j`kQ=%|1E(kP9`WJ%O)nT#mD~l+W*Kps2_7*Zp;wy~5dMc;bz22%$XIes z$P`_;zN`cj#5VSIb6mlSSkt_#kM#*uYmNJ<7~Qjot$ggD{V369T_W>Bm$u8`GN!bv zYIK^5g`4eGgw-|oV&cWS73Sq=`V-tYHcJ1HhbzPftM5kr^FSj?)%?xNvN=_{Bw;G{ zb({+{3m1y~4g;J-kcvvxz}YIf472vGl9_gPO-S-s(aEFmIcgZKoywF`Fjf+maJY7F z6Q3CF!IqJBsV8}#v0X?P%>^a9rjnkgQ*f$Y2ez*9_@MY>IqQH#4Z!#S!d#Xg-{C`} zjHki7(l@{Fkoz*}`f!hOB|#$0%`a&woFNte(HhodV0J00sA$2AFiC--MIH9(U2Oq( z(O2coxj8w4BEU+E0fbLLvMljU1I}KIXV($A+C6{+#r1Y$-5PvQjwrlBb@y@zMn`3L z>EC~+jv`+SR4vf(xxfruYd%J9CTuVK&XpqmRS@vhwQ45g?jseoTlbzn=%iNl<7M9K zO;*PO^)o$0K_%}IEwH#JDeZo|^D>0=>ldi8x__fhef)0&8cF&q^O$-QXHooZ+ops~ z`TW{QqD)D{Iz~jb`SV|bn`PvJ1&Vu(e^0%%WmTAuqGv`&wsTlyroWsNxVCLsVIH>v z_ok?aI34;Kj7a16Z>cyeTWzMrZsT&PET9K2vYFAgeS6^W@E!pg6ZE0HX(hCWt=jR* zeDYD_Vw=>?Bi8Qw-tGIBFLDP+0x3Kt9q$YydaE$}Y8bh9aogU&8<0oSX}wnmfrl97n69!f zEtyeJ5SHPIH+dH`06SjhQ(VfPo$pR@Hk$s*>ap+Mn3{F55I{CT2BewZrGvNIQq7FU zyrIC;70Q}~kE|6wh!#X67jMfH8d^3AY=!6$7^Nf&AMnPcC)G9155aXvQ=zf*{96tA ze02+=MzO(BZ2l8rX=&L{oUpVRI~=zO?2nExp#d>qy@oXiAGCpc9==ohK#;|vj~@eg z^&IHH-)3M_?m(j2DC}7#HD%o)3ndOl3b>QCt1M*W42&xL~#Gu)bT1sp=S0wg5&@PU=PPPkH0vZQ7*$_+!Go>y9 zD98xUkRr!u#+4z_F`*;Y9r)1+;)axv$1aB3GM~aj@Z*BjJ5T?jcUn86(_?eGY4ZE< zTQ?*t_`ra>Mpra@>05UkoohI5a^B)g(c``W>(6Yl8h{f_PJL0!4U7!xz4}=Xe)PDa zgNmL<+2buM!#~c@KyJ-Fa3polLIyX4H`IxUP4#sw<5;r4BBv$uujt7PPC(wvx)PqU zll}?4ybvD=kt3o~ND{u9(eHg5Kg+zj0#wKw1@=O7LWlA7OY!Kr!zwP9 z(7lhL3>0$+M3;}wm6s1SF3+=}!lY3bS;@WT0+(HaeSeNQFHu8=)y%NCb8HLrxTzlqk|59Z=N=fTV`PN5&{tQtXp1 zgrEP=*>q#Z{H|!(6%ej^mhOMPDX?IGy5BJy-R5V`qxfTxuPg-5=sW&dkjacWbDE=t zLHZj!vI+$WmBUZ;8o%Eilvlw}t2yiq))}=+_O&mTPCeVKXV)3^9X0L^o%3f@eT(9% zy=4#jy)Vot$en!iCW;nHFMb-_04bK2>U0^?`yFUJcJk+E=ikhVZ^KZ#Y~`$@$y!ze zm))Aq9qrK|r zc6;j^bUu^@mrM3=L`^6ZK4YWI_&VSs^zrkcwb}doCOCz~*55>7Nb`)RMZRXbFbooU zE?EVEfxeUYMk1tidUM9nD2i4gH}OIl)zB{Ga~Kb&|`n_!_Jjpu58I!7r{99 z$3zQ7a2`=8bGxIvYThn|;YZBjbd$6@qj~@3Ekx;f!Om>eR|F_>ok_eOL)Ob7jLUjERm%e}fdMnx@cuz=(ibB$;>x9d|lQmWlw3?>t5UVSg#_b+hLj=m= z8rf|}_2ehR0XHT+Ei?1|ltVXMyEv2VNKWi<_{Xo{AzIO$O5#?#1mrja10a-@>?%@w z-Oity(WPY(jS3lAw*W2eJ<6^;vCN#J=dC}aGejbzumh>;!bq{s(Qbbqrdp=Hkw_XJ zcAdYY=K&#+cU;V8B;$fNM+*itvP~l7wAbq1tPLl812WgPboJw7W(aV)O&?#QoQYaX z4EiV>MVBN>EaAe$1yotkvGa!St@t~>KiKEzrZ~FtKv>vLud4S%ereNO>kJCfe}ygm z{HhPrc6A?XI)y<<_UqzC6S}^yD|McYcQvL_Da0A<}=Ew0=K5-2g(K4Tq(m=?{R1OYzm`r?3BPHpJr zjMm;VUa;ot)T#1IVYl6^!?O=A4D4>cW{zvfJ>-FWYBf5ENe*|Xn0K0I-lR~IL@(I| zC@wH`$AL(MxtSy*1(;J3#BDwHRD^!qb-ahOX4MrM$Q2b%V{Nrml*L9{;59A`}M1E(|@?jjkQ0zS!k@UO4n)j<#Vr_ zg|3ELlT4i#6$m%Oq^#4cSL>K==2PVrgb89R>rO7BC^mtKR-5>owLd>0(-r6Hii#X6 zO9{H6cX@+6DuV%*5Kac&)mrpQR!4CTvSTK9<}Z}ZGHzDKNec0ME%A@^d}2nDR-f^v za_D?@?ZdkDf<|GD1`_GlxSE5ak6T096H*_eOJi^o()GsZe&_6nAT&2d4Z)2?rG3w5 zYuHkj0-Szu&gL zoj8aIR@y$AYq68f{0LnyODVgL4IGIF6_^(!U0my+*|fOgn~i?@o>yZzbc{fj!h6aq z-d~ttfj=~cEY*-Z0`PY2w;aQr+}d9ZQiz`rs7rh1xT$UWb{!R$C%K4Ni_BNA9wLqx z0i+ln0cT|YDiiR0y9J@Y4JSH+Ldjmfk5z}?YP}wwkH$rQczT@{+D4nX3(Vs3M0`MT zNk!8Gb!XuoOT&t%Yz)rhfYqJDA5~M+gDxFNcM@X*oso18;`DZGZ?d7LP56eNnx#og zF4-SYbyUx;)`N1NcK%1t3rB}`uGycmEN?j1;@9kPoo@kS10P1`Om8na^GoM}!+|C8 zPDKZO+HG3r8Kp8A29`%7t%2MuJiqKxFnKKTGn*0{UtGDVemG@F0xTt8KsKJ@@8b&+ z(=A1JetJ+3r`c5Tq#OF!ibXBQnP#@O`LmV;ROt?zLfWNx`vDpbSS{&)Ejd1X;Qk3-u3oMo zJ_yxu2;7RUnNd5S=dmY2NB`EV;MMh^Ly3f9;X5D07t6OKKgir0Yv;41Suz~HdM`HA zD(I%p^ddW=xtN%X?jd(hTR(u^LEPoCO+Z!>5u%3P&jCDc+Z;zc%x7;nH&)e9;17zs zl?V0q7ygD6rYm`Pgn!Ay+ZN`6e?{&#@NQyl z?h6H|shQqE;e>05(own0CEL%Aja_nw`rH~Q?;ih_ z2t+SB8JSO&PGkPh?1?I-#9GN7CFxyggtskAV~iK2D$(yqo;mUgd?F}N)y^i`9DZ|a z>)Z}A_FswW_}S%teVe~$n<;RR#iwngT+oxp>LX}h=ocTQvuCE^O?**ak0pD@-XJQO zh%)#g#`3x`o8>RwvpM~zbIqg=%8e>tU-y*&E5JAee+*;d7A44I=!nk+ZKN=OKMMN+ zY?S;Xa4Z!S8dXRlNOZgFtCz*?@`2^JvH!u&%iU1g0@t5jx`ykC-_?a{nm4B3XgeKs z&5S_jpMzVUbY(iEFIQz;5Xl0-O;W<4vkjS8@$<5v6ZMR{_Flt@QFt<4{{8nJx54Cn za}i52798WfmnuSE;pTBCxdR2)90dcfEGwz9mYe7)N8gM(cJ=C^{c~uzM{=Sh<4{b3 zziUZ9kX3^s+$aUkto-iLM`LQbASHTG;nGHLOOn7)ushj zXx!=_ZvB_RfjY49xWh3M(KP`9FvWiPY4zkj2(DZJqn@7S2L7Qqdd>UKpC=yuhXA$R z&apX$&9BX#bZ;+KS5R=-RGhY_>*?A;az442Zqs&gS;@x)wjn4mVnkwx|E~q`gMrhs z+861n#TK5igqKT<3qbaAbt9?_8*0H6x8WTJMGg4-==SZBfropAoXF;bAyQ=9QPr@r z`ru=|{dFQgJbVRwDlPl&&Zdio4%a-D`cEoR8uG33|AYly+aW zmCqc>7cZUmm~LJl|CDk!A40;)Sk1RQtD~C;p_(L2!}c6oN}JLl`5?<9gI;ui z;(Nm<0fKy|feJL^ZGe#L{gHmu+iYMW(XC@12S4Wu=T5_Z0h!%J-|6VsX;?!RuiexL`dFSnmu!^ zDj+z${uoZ3I2P&OXwpPa1Gf@Aedn2-xgnp=EP1o^**RHDELaO;tncch+13TyBHnPO z1RR7UsdH>Q3U~o!z66#CUIW%&rQDq!lY+F1gDs(*{9{mFu(u=JOEWu$f}iiaKX1;Q z|6CAa6TEoQ8@~_G#`xj7a|E2j;zjRicYZ;m^9Px>A^W!AjBdwiV={TGx2-G+rVmPh z^d?_UMpK3BSFi3F@tO5oAp!L|gPMg;Tt%`ZQaf;JWllt>!a3VGj4or3)EG|2<%5@x zVHse;@pI$RHLp07=fsn|c5TqyY=9f@Q4uNBmHN-?hWG5L4BAeD#4T2~%-rGz${FPH zdRP4bkbcl_MTMJxDu&zs@#WJVwOPs#()n3cYYsBFnD(5fU{}AfFG*y`pdQ*jy-%N&9XDej?8AZ|<$2mi1PlXJVmc~P zT6%c#CZx&L)zy2hk!SBibbMyG>F)lsF7NrhC`g^?qAmDNBd=&&81W)|*Xo2f^=%W@ z=x?%|)W@Xwl%;u;Kn6S}3EKjZmP0^4(l`4LZeEgw|Eo$cE40(}7Rb9QQZ7MXvih|{=9Mbyncb)sXI7p&$s$n!4Kxyr@y9e+l%cr9+WYFWUgdn zl+0@C2vwh+x2w9}_;82Xj3pr_*g>O4hC-Utg&~ax7qlU_i!(ot3KXJ+Z@0J~Dv7rpUe0n~}`*}{v!_Du&4n%3c z{LR>1)^j$QU4M7e^(gZj%4ur^9TZ)FSkcn3YtxOKgf2Y}ab1NHVVIsT%) zF#7)G%bgI(Y~~Avhn6e??u0i8b_}nsUbY>rlPn;aJv$?!+(|n%u>s?b12-n7Qr23W zD>%-%L%G6jxGdW%KV(4Kt6uAC^hO`gysziraz>W)v{6}3nZl-kcV0cL2x9Q`8vO61 zq`*)us5PNF@gad;7NslsN7}8rw!Sdy+zbJOdFE6l<#kUR4s7_37&l=6;2BjY2qV`0 zJf|3q-e+6ItilE?A`_n-LNBas?%Lr1U);%ErOgFG5gkC!CXD)KU0P}^U3t4qH!#;0 z5{O_)XtGe9$^MZdpQGdTHE)=9dT{5#Cn;~p!Klb-E3M{Po6Pe5(D3x|o*OzAQP3Gu zMW@O`oD^#G^O#&7qvE74~EB`nEzG9D4oF^vZBZDC)y8`q#6sTfgRNMxvcmGaGs@!TxiH9*u6s z{ySt--G2*jXdh9nyX>EHnw%_vTiJ^Pe}=RRjb*`%#KOZH9?j6Vn%ahfCIWAe{S;a# zD7{b>Q%bK~=D1Ds{Jk|D(W}!DaN@=(rf@NATWB`#{=$MIl^Z9rT9B|_qqSM{9-X@N z_}UexK_A)o*Nonh8Za^L^xXa%oVkloSe)Y+&rV$Bml2Pi+mw6|@A#7%>)I%o{P{G9 z!d=8QewD^Od2mVugO)>z0?4Qsl0+0?S9d|;JL4N|K3x82b<&6qY2=S15YWCJ7}@(3 zJ8l3KPOt8VAd(EHhR_NRnzk`W$V&W^h0x`(%f~`9g2JSELVFB={l~t60|q}diNz0thCUTDBc`~&_sgF8{oMq_DxyQ>wAzl^cIMyg zoS~mVBjoto+dsHaRjs$;?fB>uCxV=GO}r*gZNu?m`7+pMdQNv${ZmMZMKwb8(SC2( z^Xs!I-?UoqIRoIcrf|dkxHufnK~CvcRtIj(Oo)&^Q)R@)zlR3(63Ih?Yi?0l+4!KD zzf)d~TXF5LX~~+!V4>N&uK4|&^{M%-?|XAAmzd`oQqR1?ngAk#1Z>9=EYyiM8||po zcq$j4|8>knoXe={LQeQy5X}-SmjeU0wpo6}=*FW~zEppWxLRElJu_#zp8KcrqeIH( z1~U0m5CRh8dwdz{aQIiwKS$9%Q;T-#y+l_?snq@>XG19Gc=PrsEBd?x4K`p&t* zw(VgyQ%_Bgle8!A@WUXs{DnvnzT`aQ9@=_BHWPo*im*CnHsji|#fudu<|a9ozrOwt z4wLb{_sx6yEEGv`-Onq@d%d2{8U8=Dz<~=7H2MJEjVX58xGF5Jrs_ecS8Y|MO}ze+ z2-~=?gwK@J{|&FdGqvYo6R-78rf=%Oq1WSe$_O1A{6-J-xT{aIdC7M#Z~gFc(fs+h zmRGZH%dzhH&^|>iBD(Ju{ao7QfB&tR71OS&s_Ko#nT$g( z66?0X=upnwvuVzYHuUsxr+_G8cby@h%%fqyrZ^^zvy>l)&yz*(z>$_8$-)y=+ z#zdo|@8s3bU%m{!^kf|R2^tRa7XlGRN6|}DLo`g*81EZmu~adGU^5F&d3XB#A) zezA1fM*cH9qnoo23>(z)wW;OG!!=`$)NNdlxus%gwu|ARf808;cx4+Ta52}P(~pKv zQt6K(vRynim-B~dN@o6%vCuxg9nEjjy3h}%@wBviAA&(u8Q=LAOxbTehOce5aXr=^ zx%uxi-Z>Z^+d{VuKoX%gZ!T}oygXR1Mtxpe)7%-Ys*|@2_K#%EZ(~TY^704Q99=`+ zCuq+9Ijqp0=6S`ct&(D}aG|VP(>}b+<;JYUW{0oe*)t%!9Z-O*LW!Py_GZDu@Bh}W znW4~>j8Tpn?m00;(R#cLRh=-kO;4*s3Sud^wj#C5>tUV24r#fvF{rq9jNVl00p^Yc z2X;k!&LInjqToM<6J;}08}q$uB73Vy<~I^l1mdY)o!=Kc-7jQ17+5=6!n7Bbu;59T zhfmCfd4?`ZT5Z}{!|Qf?4T&Q`VzZq+PYJI7a^(?xTR47(KA93|kx3YERl8HRa>4nl z)AL&>z)p>$a~59!!@BLS%aCYDQv5nr5Ba+&V~%X2${()a**77hjd=upFJHBF+x~4- z#1=?tPh6v=rR7=MUu&mNM&H&+e?w-qk0Bwsuo;s#2-(XRTTV{TNt$qt>2)szBGENn;SIbz6R$VI_v`d zJ`ZS9O}R}LvSS)R70tZg6JrAVh`xu8^{(7>@Q zo58c+tjc;!ss93A`Zcrl%1Nt!b&tBPre(O}X}d-#4-Ez}@(OE#7))~8up~RW*R!*a z!7FI#$pH41D-86m&d}Cda_3;#rw<=26hHOv;g4{qf#>s{rOST)`1ij%qh9Gn!xT4{ zV{2&RDDq5o6|0!C=HY2hsarBYuT4n6J3!w=>oa89X?G zxmvv3e703H6=cae5GlwQk#|RJhIY`@jBqQwiM?e|nbmn1bOs$N1C-H&I0p&;c=t{s zCWyA}-Zqsvledw-OhWt~cAYw9%4Ys9b|*#v!8=)jA&G*^`RMmw;WvwqC5KaC1*^fg zfzj$h=3Tbz2^i0x$sY<3JOIx@D=n=F`MaiefqdLe8vZem#J9hZc?ix=A5Fjib~snJ zB;0|u*e2T*Ellof2qolN4`A`=>mb= z)=2U0?SC71)hn*6M(Nrmj;CT{&5-aSrnUP;7MeK%K9`Vt&?-CbjE|UtOQ$7mJe#X@ z^$ib|+fj2c4OUf{Lye3&kARf>QSzXA?|)$1r_`Qzraj}S60>~%M$%?R1E-_O}CKs->*CeOcrL@A^`S&;r4=pa!Vv1L%>LR4njPiMf?Qk}>E^QZl*p26g-@4%_yT?e7g0Vjxy@4TmaU32Jv%SC1;2~?t>uUii>0A(M0`3SpPVw-_Q9&2 z=F~FrmYlwXUq)Lp#jUOHylmXcQ&R)};2(r3_`K?EgOX%VXeL`)RJQ8pC0BGaYA76uRKAVIj za(Ub^&D`q;e}6!gPu*rRQ!Q_uXz=85*m~6MG}rLI-p@K1P8?0jAs-*24vZyKVQWR{ z*AKVcw4x8=qAq#!h5#~&wpYeW82Zblf65FHbq4PQ4ONGG8G5Q#VZ+)2$1`+ozoqMr z(o?n}_Y9_|4E|@c4BqfTR6Bw2o#wJvTpx)meT|@3bPi5pHsfFBFVv|$dH84!$SBa7 zb9y9I`&-3vlxkc5i2!3b2Esr;i%ql35*?tN6_F-*d&ei+`&{E?g$xoqKR-u&jRpNV zr`ONz__=dmE_p;SouHZ_0YwDb{pKv;DvUQM1iTQ1EEoZx_Y&)pRG8QEo?jQR45Kz) zsWYz_wj*lM{L%#lU8(v9FMXQM{}&wr`-YLpk6GV}cL4lSRARDeddV+da`27rc!kQ& z^WP}e66c4t@m9){xUEQE1`l3Vbq$n7l{GnAVP;5&tcic#DRE=#Ie(`8I_j8zl0ehy z0rVG^nXxE=m_)CQ_L!N3|IIAd5T6O6sZp7GFu(n+t>st5E06BB&X`x4Uzxe~0+1d) z46ZauGR?OyD@+G&ub*_Hx4)hab@_tRL4G1`O~s-f44#D z-Y|uX1*Vdo;gfR>Mb8I92%!^v{cvP&uC^^FTvas0joHW-vO4nGcLW6z#*0g4?@<5lOlAWH=z^^&R1-!&)T%#|N%Th&i9sRdR=EtdJwT zA*W6@(V?J)!w}R8rLAqt81Cw_ytwwr?Ihbin@}Ka|j90MuUmPi=8oH!-eFdDPk&hFpY$mnets}ovtXe*}P7(N4 zfT&Bzgymxg$}RbuQc}&=;5TXo*;~X@%g_2m(YeKX3ilMgTA>{*j2lEp&TJRAd2G2sIE8>;<VqDI;R=lW}~NYrmJ7XL0GR#zB~FKr6?KDopZmQZLh*E6_XozbSLH_H_B_43r27+khWiR2MU-!R znIJ6t_UD22Z->(4>r|8nVDTLTg)di3Cj^U;1xP+`gENY(RC0Tv|0Po0-MveC1Jahe zI!5(Y+4T2o;}cegB^*`wro==owyI(g**q=w?v{p)JqIKd#4ho)`7~em?JU9IxXwa%`_uP$>;F=B?^{d|))KH9=LL>{;lp z$m3eE9t4=k%gckrGU4~t=PzE^z}k(e)Yj8`nX{iF+o!~g)?T69rZrU|baiYMetY{FL(JC=3dkZW3$g=XOfy+UqL6H$)4 z_ULU4WGKWMHi0ZGKp(G(5#8OM@F*_e91}FXiq@MNRvFQm5{!DuSOIdy{geUj`=6I8 zoVc)C5OFVr0IJ@4{29(>uT4r6g_2XQm~Z!!go`mC-{@?e40ADNx_FIQf^&+8We*k)_w^ zYXD%RI)oEx;&K_Y3z;kfHb&moPxRybq;l!mhH6wzNwcSw5821uKk$YR?5qrmy67n=_-NaKDPM;7+a7FwE*P_+p_fm8-@aE2x z;JbqJtJbaS^)u~;)#-XhhK5^eQtmFGOxEA<-Fs#)ONRgGdX!knGB<@BcJGD_1zOWC z25DiB(bw8eUC)`-fci~YaX@cXU2bhV|E(XJ&~ghE`=PckFtl{UDb%uShMkA@LbO+*fcq)_X`poe0HA%JXW*eFb-C-tAlK_sU!J)S_R;Jl+x&1l(v0mc}x)LPA( zz`e!UlfvuKX0k4fI0ON`^2@$vrZ|{s$CmFe_~*GxS#%ptaxp}g#Uzb84lis{DSvYc z3hGfcf@@q%zKp8^H88QQfoXwL`*<_Ap;KFl<#EtRj;;B0Ac=^$7N8NKdODo3RA|_M zaIh~K=zsO^bONjZCz{(jD{xf+BV#N69pk)v=#pfJD^_PbF_XmvW5Dg?7--2ZrJsEM zqax;&Lc9}30rY7LrzWQ9<(b(v$)9ZQ&N#_5_of_B3P1uC@rj@R`7KFYCf`I^BaFHg z&DX9kZa5VO01`p&@zd@ues28DJAHGy8TpC@BcI`{dx0-6zo*#wdx--P#AEP;M4BK%N*Y5=OoAXmw_Ew^ ztIfT1UXk>;w7w#0EqRVsIsR5pN1{LPvpMhdULCzvN*!1Uw2D z1>TJJp_XpVx?Qf|+}O$vaV^c5-Lu=SVMgpYn~GDS3K8lG({uq0pnJ$*7L5(?!)p7l z02O>(%Y9LkTS(N0^@JzU$J}eHo#gz-CYeK2!)7(NFNhoy%VC!vs?uReC`FNc~=&J!U6WqoE1 zq9Np-Ik<1C1p6SO>(;ZUclmPqs9fr9q(T63r|%4D2n-|&S^lBs*saj@mxb-tOi>#w zUiYFcB%+97X_EaTT9uV3(pUk04Hjy&;%Jh9jjkb)X+QYTg)btzh_DfcRI3{^e0|3T z-@+%UGiAP5?GKyC9?WJMVK^8lv4r_Gy3A~=$ew&P$Vo>iW>lK0YyVS7@(R{j7Y`&u z5xA|r_;8qMui(^%>za0HqB3rp=F(U63wbm8|Mk}xw(*fCB<0=)vA0N^b0(wZ?}2>d ztjYb|KBQ7faioiW^k^ET4tI=%=^fax)X@>%suo*D%0q}da2L5bgx&x7`8k`v<}spz z#FGG`0}se>;NAT-*V(Y|AD^n`=#uk+3(2H(Ea$WMVMws0(Y-rq4ASjp+O@^u0nLVb z{(+-?@DXpw!B+S*qOpL{t5%V2C1&z3tod~&1OIUSbvMh*8P zcI2db_!@tcM;M-wIN!?#j7=;b+^b7xPbqEzUwKxqx>2=i6FXE_uLa@eYsj{zG&+9z zDmNbJXN32qx0j-h z6G8$Uh4!3v7RGd zl2TvKlr6(iwh4oTeKv|0&z{l0pEnKYwe6_Xwtx@ase{-)i~3VfUF63$UH6^iazd~D zHFFUE#ALXSykUcjCm6c+1f|qB(dVAn===}@5>?OcLwoU4mI_A{bMjbYoXR;51gB-v z^?l$Zz!1hIMg%Z0qlRIo?A0XA&2GY!!qhfK)SbpGpWO|$9!#Ix?=&@!P#odI)!4Rn zl;_HHgeK9VI5ImW>YPJb4kx2VMq5=Mt$YPZKts_oSeeqR0?Z zEoCluhj?-n-NC+xDR@ILhj;5be>y+YVM>yaG1+h2Y6TZ4zk-H}eAdcwQM}5m69) zDW*8&3(h|ie6E{zn;%fG$C}~PEk;8;rsUTu$SNeni(%G9tSwdtQN5sFr@g7enM;8a zT<;ck9wkJ`Nc1R2c+WQK)E9;bk^r_&&P2n~PmDDfJMD5m0vd=bM}qXAW!dZ)&hDL1 zfh7J6Sn9ZWITR@M6n_SHb#kxV?H@hI^z>oD;1BTX{6!N12$E=dljmd2fJsnARLp3{ z#{LXoK(KOc8pRq>3o<HlkWt%=s4M2G5=C?ExYJ@FLo83pVX|80_kJ- zecoW4JuTw(0$`V0J_21)m-r7xhW^}Omr_1|`m~aSJ&cHarf-OLDP1bV5YPdDkFI5T zlyqW?HDy2{v-u+oP_WVPc$95N-Y=ZHpzuBjv)+d9J!QdPtZe^w zrpJQ5`zDeN+u_+06bTmyMg3Wv-Gy=5qDW@)StC(8exqyyt^g^D-tS%87gQb8TborZ{%K_>3x)xD(O|sm|=27kM8T1U+G-u<&^b@9M zs~H80aDZVFN#4zk+xs>t;(dwf#D^&_+*Fd!x7#|lpzMazz%}PjP7X2LGiAS19Ph*( z10b&}*5Ftmji8Z|q2guIf)%DTZrX$?Q#5WEMAb@9Xkww&zrS5YU`S;oV7f%c^B|mU z<193N85Nk^SYk2?p>xmtW!wD^1_%2w>$L`s6*mg4Z%9DI@LfX8O5M2iI8YBn+ZELB zG9q~Sf_X+ZPfMro3knihgESK$+IOAUdpU5x|1gJaa9y&%M?}Ny&>pS!g(FJIlJ{llxwY~K$IWb>Ui;hZ2gZr zP5SO5kY?M|fzftjb=n6(rPF#ipjFHwgRqZh`n7H}?DO)%*mWN+MO2G{5d;}t;P;Wx zfaV&6wGTr*3*BIjeyiU$=yH3xsWtg4C-O%4+LT4hmy6SG%g0N<&f`)e90U+!+T6LB zr*}VG^b}T#q3z43PK5^9ulLuC`c*VSbDKkLm-3BQqT}(iO(q|`XmxZNPDW1k+f3`xpwWZ{_b=JLFZ0U|>5^KM z*f%t6|D(?vzUw0~8%f0wvgYC9hav9+ZkFg|?lB9xe-zIfhg8m+|mgghOgu;3mn-**caJ^YV?$?nyRun^!*mJ<7h* zgYdxj0e+8q*TlM49k#Qy47uave&zD{CC*biKX;3`?z*&ZvkoslJh)h@)_K;(qpME7 zHjnj)The0t9jda&AJ_hK`gGmYOS4h~qpKW>t^)frJrLj#A1zK}yT~(@u{At9Faz&R zP7do{Q`WzP6zL&DX3H<3p{(-{_HcDW$yPMp!y zo-JRkE$VRM6!kY3{E+O=j!SM1QdROXtOMMm=5LI|en_V8iXwf3Lbr%jaofW?Su%bf z9Nziz!KWAeE$7W!c5#K(DgEoHqwIB$#>Bii;mWLX^WXi)gL_4d3G{VKIPrQ)(ETG? z)#p`~ocz|zbU1k7-V?rVZEM=py>i??d>DiO_1UQwbI+XV_~PW1%SxgB%$|SW6*p?z zoji@ob)gnZK8L+Egyj&yG2&5`=_WAzZ@JwF3gJi?lwKhHtcQiIUD^L=@Nkmc+*t8H|{y? z=uG0PD%kCjN7)xlA75}CY;gX4&D(4GC0`rV9C`HqzE%a!Uc7G-`MQ@pN8 zrAn1i>J{}khAPL+mju3xWO5-iI;7ZE+G*wcnF*>E?M%i%? zl8BK6T9w3yP|Y!w7o)eemo~+Y9Pm?eA{!v-eoD?fpf8~b%{`uc(z6o4@fA#qDGp|a&DYg*|2KKi1 z-W4Zv$|J?&`EVT@+SZZZAb*bk@K_;~xcm2y?&vE2yg_wKpT__BpZ@m`6_kvwWA#6O z;W`*p4Zlm(2LYdvP^sM0U{P)tsJuRwqzZW?$ln|`;)lu7JQRlEPc zzy9y<-x)h$hNE}czKZ*4GMDR_$5%%IP84LC z9fB|3oam)K0C?h{tr3o3pfS(i@q4ARR~<^r=nfM~aV)_+_Hg>g3#hia_H@Heh-Qak z8(1%ynlkjw5U^@-ZJRl>&8?c>4uM_uA}QU3y-!j}$|_k#;1ToQjfMLG+gz}gbF(J3 z|L;e+D<#1DQck3gwHi6??YQ8hDn>9Y5@$D%AS6l4e{F!755V@cz~HCLNQ$Y&I*PPa z>WAEZSqg(0Fkv)N-**(tjKCzu0+m3U-3Fd8bfYQ~MZRRG3v?f6D(x&qZq%yAg92cN z)t0TIfF#0OY7yaf{{KE#)B2uW)&O$x6MP^RQ}08iv09hOKSN(mDOkbiUR1D>AOH8? zjwKsSOiYjl;bc``07yHpI5Fa*6wnJuf`tNADXZWYEs_0;^PR*ej#7H~se(<^vhaL_ zbD^FxchqF zB%_FqjY^Zwl+44+uXIfbe4<5?EHu#L&^Pm$mXqoPzzwSt%2CDif-_T2dT}4{fY%Q1 z#2tC(>ki`{+z}Rj)suRt7$SRnj=_uc>8Tif2>_~oltoAUKow`005`Tc!} znyNjZtsf`?mOgKEfg> z`r4P930B&#Jo4A@rxI4F)B0Hi`HbzpX+lp!H@DbV6^_?NIeeJYv!!L)0QV&>Xbc&! zb0mJbuJPa7>7sAl_?;JV>0JByc@rj(5=PAjzVlU*eJCLD(hRA3%ML>luC1o}GIrzD zJ63NbWBl~YeiEfg&i9fbRxj9ju-nkP<&g5(Zu5fY0z5FI5}Px+&tIb+O~<5qN2d{D z$bb@4;d%OWUv&dlHHhSAOgiJL(HREOZ63eOKf=D81aB;)kB1Plg#t9h^*wkSU7KiE zsMXX{x{Vsu1?RPR`jiJxdj{SUJYiI8&U9 zL~y8>*7#b>zle(2(458ADr?ob8GY+0kfdP1zscl~AlbOV#m&~4*i*#3X#IpE$MguDtF&zOHOTeyCFOzQVP`Teoey*;GvAruYF{X&*j(SYdpu1xN@>*jZvk;gILPO^uJuDF(X6t5EXL z_67$Vk!yx3Uk(laFXQ{ub90As$|w{l?K@9YyyUb29xLk`Q`HBBD4@upG{Lc1cjG@}BFwu1jx%4-NS$&fW2uCJ zOF9DAJe4Y%5d0NXBnALK6XW&khs?D5?@fDsKx>72J;;Mx`HoqKY%OV~=c=|g_(uZX z*&r|#EQmw!+*tgBJ8873ssF1=*N!Sl7D3`kpvZxJVmC$$gd4PxxXgu&B&4ZV^Br?$ z);XCaGdJZ$g}E*Uu4Mxxu`MNCGf)!z`R5WP)~SVKE1Y)E~dl6zPv26t&oS#o^{R1mb;!8CdyASU=X?};|NX+8GOq5 z0Z!fgK3I4oTqXok63bGG4}~YH(aB6uMU{ZcY$fKP3IT9LavD2-C%mqF-mJnCW^=BP z5Ew14f;3>Qp_!x&;;)i=sT@S_BBM6zt$EzgJ+RVefTU3;r+2t(OSU4$pvfF;e-%sz zZTg1rUEKUfRsRgUW4o6@HMT(we61PSMfk1$S^F4g=WETMRUU&(sTjR{`T6Fa z@AR5-oF<}kMTIkU-n{CZcE`rn1wXo=xt#-7d^+M|;|n+qA78W?k1#C$)ho*eL0r?y zG?i2%iEvMR+&Xbz;M-w@%Na~6AH_o};OPd9uRa;fb z-?&H2qu|+?sQX%bEBdb-kV8}62*>>xtR%#1pGMa^qEAs?zyIL^9Mr16q;aE0@vGE< zh;#DtHp4i{r-tNYxbU%?Uvf%K+>GhdZOm_N+SttT+lvj8J~cu^NfU?Ux4M__l(pA~nHfqY|r+yweF6S^*?0?RmPo~-P9{stRTMs&W zozzQ&I_`Y+0TYBRVsK(LV+>OulGCuai zaa7fg7x?K3<+H8F%@U=C{6U#2@C&^tVH?EFh42Y{9rECI775@;2_K&@?I_!yqDM)= zbtVr^$ZrpVDr=%HwJrb*?n8mJsKoV6v)vQwQ4-=A`ZVvum9(k;V^E$BBn$cU1j*Kv+xkoKczio?i=V44t)>S1IK#1pk3?#ok8Go(12eyoxXJPk{>Iw}o$unEU=`2Vt2IBEZO&yk<6_JI zQ(bZX>cH#uh9jW=*eO3RFJ61cotza$5NyPNIjv^-l3#sSuBga8V&wOFud=({nTU`l zRoNCn)k$7kXafXp#ahQlS8v3K{OsDAp|rt>c6!x2H!MIYWtEkhvTD-)dKG8u^Uq!r zdR{8;Dpr-$_w1Im?=PR8UCIj(r+`tT7FZ;Q)iMYUDm?z`PKpSag*;d?# zp{t0~a-c#x+)T11u!i$?g;IEDV{xn>AWnHj#mHHcIu6x;;U7Hc>I~oZzMJMp`aQ9~ z%~nVYvh4l8N0$7z4O2O`(gY(w$$CNW*kg(%mbj_=C~7xoHylN{*Ppzz42;>a^x#$6 zHZbFX6?3hvk7Vd>zzGIsm4-+DVhhw4Yrnp312C^s5yN5tNb1wKugl?H=eswElu6tHaC)F9bIteT5=IF}fW zOT+LD&dyepsR~bWI>+tbbiX(~B_*ZjIn^X9_K|)1i6-JvrU%%{|wrod8Dgk10$!;8?FLK?)_Y8CiJIqCtOrK%^2CnBmW* z6kq)2x|dL^hYxSG>0>ewrSM_kHF7Ugn(9AWb2qM8h4rHjk!Q{rp^JfUD;7I=p3f`C z4?$f$B}DTh^leUDjAjEUiJ8)vy_^pVA1x@o4GF`8w3JN$>!{mRX;>#GWiklE^Yil@ zN}{-%?YvAF7IU%*C^I6rpRetG$Jp6v%(=SUpQGa_ln`n#_-)DJdxm8szBe}XCLS+ae)vE8 zQh%yqe*=-A;@PaGs!WAb?J@kvN@htyABGkpc|`i9&!#Ji9=v(BG}ZX zBaLg2{bZt9U0F7_|KmUI>vVMNM@-R#ykUK>AV}&Q78{5WP!$E8L}XL`o?Q^vnLB!5 z!p1k3ql}Lws3A`{m*k-YFp0@m7ON@4 z05XQ{PQfT3A6*+~@FCcI_&D-m`oE1Qmzb^Y4s^ zJm6ATNpz<8adUe~Q>Jq0V_BRo3E9HTI(~et^UzPU&f?u_@T>klkJ-zn7gx>f)7ts- zxvR(}8!3do39E#xm`z-PwI-n*Fb6yEAZj?pL+Yi(FP3xF{F5tR*SPQ8WEM#Eu*A2# zdUJgm>hUhVxXXs~|Ghs9 zH7nBVd-mEhzExH3;&Cl83s^Csi!>IxbV*>>)gWE+CIl$e+IDsZCrSy zbBE4>5^(wn`J1-|LlZ1S7Cba#mfGIG`=t>h65o_S;Zr3FE@tRBEJX@V!X8=XuS zzkT{q&fV@$l0vMOX{$|EHm4A?&{R&+ZhLiT2Y)Ne&zsinp0H?LPMVcA@jU>)p0<|o z(8AJFv?oVpu2EM3BZm0T8>2_vo|2&Q>CVCuw-3xOiTK3~YdlVJiw1_6E`fbvC*gAIM;9{*#M$?&#ZBLCxS6`9oRbV;&r;A%urbVSGKbBq+F+k?t{stbX zZ%sd(x8AVgbd}}(ljHX-)=UM}kYqJTAxzGj^)kJ(_vDFyq@d52uiwbGKCyMwVva`G z*jHWN4zAH^*DhG&b5nx_#UBm~nVsD6MaY9?+1CQ>i~b%uv-eN~_qm@e-8Tl=nm$~d z^xJpT3$0U+0Jz3>pB9zlR1`>F6%RBt@ozlGOUsmwX|%VST|TQRR!$G#churA`w9#c6XUF8xB0{U?JG?bmr)v1YpGM-*M1;;vSZC{zYs`Fdep9C-kltBaR9M>@Ek5BuyeBqQij^opeLNpp*iK+H6}Ij8SF zj(vU)=spf=^XAQqTC&ixEv*C>$B?VjnLTj8bI@*B@OAI|?H<6~6ug(+Mns zIjiM$#%+jmbDU)RG-!B{`{#k~*{1VqcOKno^VMR9@v)UnKCZpdwydnntm?%K927V* zT`$%xsj&V!R4>4Y9{}eIL)+!0q0VagJs!LrKs`e-C@~`F9EDTI#i=s*vFwuXS9=}N zv>!&XE;hO#u6WRcw;{Mlp(2KD`KxUcgL@=_hL7q(y!7!v7U@b-=7g^fDyX|;hGfN~ ztB=0%h^d-2&IuYGXvrCjjTh7V_wSVz^a_ax#>6IUyV7V5YZ_CbrlH9Yn1iq(%T7NV zLHWh6=E;q94ifC;Z!BOrqbnswwAPotQj9&pc^JR=27nA#|B7T9>RCrgQq7?l|3NRj zxRJz~8<^HEdn;6KsKqeUm6cTTa#Zs_|>mdCl47?XUUx{T)_t?PDw99SM>~904At;?3ze~N1Et3@-Ye+|nw%@-3FR+HfaOj9FYq6z6H*Hbw#FeZ~ zEG=&G3{4nyiEwM~6-RNR)-19?t4T(wfC60eRQuf9f2v+~W82hh0?@WnAcL-pV=dul zmn~|u~Mfx!t5g3Hg76TvwX3((-1RVIaw`r(1SnHWesyX!< z(uo??29WwfUm2?3jtf13n%Z$l^JhFs%yxtDi~4X5+MQ6%!ro|*k|%6;&JVypv8g+wWKN|HMKqb) z)hFNWV?^-d^YccWsf=Sh1y1r}Q3rJR-Vp4zmtKu2@yP1j(3_Pp$y<4 zx$M^nFjtvXAW!r5+bv{yoLGgXz8VjOXcnV_G!oXEh@)zAB<&i7tHnG1O!9BSs;V z_6;a{s4z*--AM&8N`D3aDYibGRWY?SmCZ&rs3z`1i63ZJQ3}gcisGGaH;2-V;#*`$ zcf~fN5#U{XLzb{V%QEcySf=oE^37{LJE*Cu1v3v=CkzfP)#-AyPe4tA-l|w9 z`i&7fE)XfqhdcKt{#JA!ShojY0GB?Fu%yz5*RWUC>>H1kL*UIK>*r6ru)*xSvM@9 zxfP6+&t&&utF5H~Zz%jAyQ(NaV(6^v0FsPG&%Zsg8#jT7fk22nL1GnMnOuUK-=T|r z{^fc{I!hjoAI&13FfV%cIsW4FAD3pBt)I#)gYFQ=?#pCeNg+AWwA-Oyu*VXR7DNz` z)-v$plI&X}<$t8n&w<}Q2D|9MObBT))xR=@OUyWP753cQGr?eN7^7*pec`wLL5rM< zbW?kC-*Hlq$SETm1z5{A;0YVr0=Hw8DH9JO9WI-AFbH677`m(r(FsiZpc%)5 zelTF8sgVpStbHFBtP5uYEnbJhc6nsP)jDC$wHzQxwG4z*MJczHI>$e1zwm#t#>msv5Sz)@nP{bn1#POmJ}U)EYLlAD-ys;G7s&YP`lqAE>dM-hcA>#sCm} zf1X-n8-2Pj!-Ib>Sg;~}Mem+Ht*XjP$h|)Osv54A8Z%_%Cw_)UJZbc4e=gE>bM4&y z(gBgfqQLwfkMw`2wr=E;@#`&!DE=(pIGDSQ7?GKGJ!b94mUuI4=UkGp3*8s%CSubh zDTJ%ErYWxBwb5q2NA)_fSw_jXHvkVbtlWo8??q6~Ja_+~ z#R2yY`%l(Lf;`S`rkSS5U;NXODd}cHiP|vU6Bq`3n_r51K?ygz4H78CgoiK0^82YK z9z1!WZ=q|z*z)U)Os?k zfgc8|rYY@0VWB;P3LCtOKsdLVRNM@|am>2?)u6~GJHu=(k*Zq8tgo>A%YWyqtgKu2 zhF`zFDeBv|mAQ444K6tPQ?5u3C|G)6`_cZNI~s(aZF0e)?_9osJR8mf<)7UB0!e|< zh1MU#)g!nT1|lfL6*TZ*!-fHa459P;-)zjSb}8-zR3B~wNIZ0Ew|qO z)Ky0zX69gk65+v12-82r5{dcwbduq&kdrSy`+T0(eYe;ULo#Z+c)I0jES;c5NlG?# zO4WqA@n9ufVgQUvqLIg1B<$82)GF*0;9^VF@3k$!H9(+NE^vL>VL>{79P6uliroA} z*5x1bHK@6qk6?fT!4r1GauL@h$qd+@{ciF1A-9Sx9cJH2PCm*P=1C+C&33gJvMX)- z&YdZcpiPTf0X~Xp5iBpUs6x?lrErc6I}RQ^nBk}1F)ON~a$9uB6xX-e-?9>4+`Do` zrz0+*MhNqn5~-;2kzJ42n^8b(|@Wl~P71KgMR#8~<`7Kwj2e(xlv0jsfPSMeX zS={Bf)z#H9iarXO{A&HS2>oUIPf))L)WNBSW>-oBBDLAJ7}qTNeh@`wcP*_ZoCX*r z8iwulm{0PwjX=3|T5i zmpXPN6i5HuSthDuYHhi*Kz;;4<1mD9{*9_50ku=la5!WH=j}wqPYuqcwb|AZNWTXx zE?ip53j)n1fB#cNo0+xS><3nSZcelzSyX_3l0Oh~S?BHBw_^q_iWL;ABSJ8z{^;y#%WkN&{LKUmlK+G+~A$rk*V|f0{0OJKVVBI;UbCwDHiZ|$L8k{g7^ZJPB_Z=ePDE3K zsqgUp`EY1sQ#1V%Z|#lzxvZrNc17Bpo7c*}aw>nsFfP@+iyuQ;za{N`6U5_Fu6QeL zv2}&YCEf|#je=N11I_%YJ#YF3n^QIUna9va+l5#E2(P`}%1pn`xmo@6ccm<7#h^(} ze$!^7f4JRBUN(lqD~48$rEA2f7`m8X>?E(iSw%b@ns#en>btfn<0-;fgKLM+3+!hm zRS*}59?b+JdBrpZ+m_#?+WvAzH@GU>R6gR883-XG`ma?8FCF89NfuPOh3B@ z__J9I?WRmm7+2j}EI|Mqs6sD97b^ZF3Qz8R8-m`&ztp9y$RGYoBP9d56G^?0Y!_C% z4Uxm9Cp_4DC{Ge#kqEEIdRUQ+Dw#S+(Gs9O?CBz}xW9Ne!kw}RxraT|;!*o(Gz;$T)|fO9K7=Njz#Li{gZz;; z%9iDv<@}vpxP!*H1=<~B_!H}k-u$JCXzNC!sQnBqML8)dFMwK6&#^(YafEfuifIpP zSjr(Y`2y<%`(sE=0 z;fhUq@O+nhpLDqFF$a3F4=L?nWB|H~m?%37> zuzho)Sm2TiZSuE11*jPAi!CBUeX5lR6A^Uz?G%86O@MJ~F>VITr%u$k{y+b=}1sH}HPz+iArjKfK6=mgx zOac|2^t)sBKRJ$ZD$I<-{7^ak1yE?*thql{@XYEZB}qJJx)uHwRW$?^p@FcdG@HI* zVTflbmk9X6MZE^kr-DonzbiT5LiINs`DnnTtf}kP4Mw@+c&R0G;uMB%6!3OKZr1Kh zB$^}pSdD+>MQP6$Ez*BJ$;N|fTO-O&JV42>iyL>-iBC=&E23-za>Za202t(zzF07x z15*|N($dh3!Kz7JY48}olV=lhZ?gKNGOK_;j4%drQa3OCMv*RP1H?66iV!WeccnE; z-U+vq(sAjk4Ka)c4sCefe*3b%lTxs^@jQ9R<$ghe0?Gp$9BYNy``uodbFB&BM_DW> z1E@eh9_c^s76=YIY)&f+GtW#3~B*#eJ^TW-JO{5AST+HXBZuQG#_ObW!M`(1-*j^yH{50$J$1}89H z1WjwVz_kSpR}!6}Ol1^ho1=uyk)$muS_)SoSrSGkWhyuXbnm!~kbPJF#4sH_iehCm zLP0fZDnQ4 ztU$>k6xSWCip=J||EXtEZ0N-0?uj8TeOe^ ztsy3-!jg1n3#u5T1SLE3+rQCJF_5(4MQc=K0!IJ}Fa);(D#gM}7ch_)DIc1D-+kDy z>*EI55JoGJ>cTC9$b_H@n#uGNlgD61tc`L%uuTasRst--zDVA#nCVcw%PNnu(jPz* zON~(vu_?NSr*^3=leEj}<6*7%5ORPG>fJ?}TVw)KP`tTrycQx9fwp>i%8<<|gLsj) zoHY$pRlVcl;x6d>Gts11V}JG2fAVk*11$!6LB`8p{`Fz8|96iOFcfHyv*!6c>M_)OJqNUP*WG(c6g-7>4qR=DGUr8_rRdf^=Evy#R=cmqLzS zjb+@(tec;=H~h->!pOwK(fjZRs+m>nNI^c>rioTt4UdeTFrfj&@2%849jN|?sCe2A z40-is*9nR%Syzy>G*j~+V@vO7>6gx`;nBj87g%kjFpwoy4iBxm)QP#BVodk7nyWm( z@zwluv+&Inhkt=li7E_JRs7hHxzgC4T9iOsJpr+(+K0Bk?6ymnv^s${=ujBfx4Q2L zw_233oRib;I{Zswqxa_~SqL6rcx#QipO{}^mtoH_8n_{YQV-8DL7_f<&u@}?O{@6! zQnjuHdQG7cBvE!_u)Z0KvD=I8O>`f9J=Z-m+QARJtt~TPX8p%9;+02T=tRUd@VC@9 z51M}Zkvex4?w=ZguYOt)mNJ@=A70ZXfUaR$_f~uyo|k?RZUfo&$H=KewQ^9qc^Ek; z)CGd6@h!lKs2?RGjo@CPAOWWWZ42`UjP2kQKcM->#b)`%k$eqacFUmk%k-z};~fdj zJP*3UtS&PytW^a&y}G2n!pG3sJelN%=FOXXGMrYKe?EHELG@OxdZ^pr4Ts*^p{@OQ zmiK0pDz_|fI%rxNnI&Tal5Jx|4$qzhlmaytr>ej@WDGBBHTE{ zg-2UWLa?ckla6OyEq#3{=#c#UHVt9gkW&?R$5yT4$2<(^d<-Q$c+9C8-2paX5G?;b z&#x-B@wKZvs;Sq{H4XZ{;aS9_c8oXiHndcChG#%g&3G2RTl3EE2X*kb_%~X{=X?5o zM5|zkR46>ku-L^b)%|Eo)Kq;nyvQS0#m_=m5LDv*j=!?k&AVBA%ZT!yGl!YHkJA(7 zdi6Z>^`MZ3W%PEnT>f|R2If>JD(fxqxK8|*BRE(ymNc6>?5wNJ(_w)Vgq%ZbdlXm$ z!n*zH!yCCNm|)!zp8+fg?1JxO?~%elrXkA!;21xaxO*xi9j~XbVCgixtkp!#$9dlB zX$+)v%rl@zb%0xEIMt_+SnOH{Y+hBG)U8{tJ^_8KI#l^!}_57!40W%!^Z`_NRSqdfrrHC zN<3e&nCZVaj!Qt|TsTLGVs2G89-9jhiHU&`tp-PW_J%7riNnW5i zFn2=Ttonme3WJ_P8%q9?($4LgHy3{WfnjTuiJEF2RC#5|w@KYM6jt|V$^?YSj%7q9 ziYCL%Pn3wlSUCZWA7D&d)y6z~wYo3^@cpBQvFtSa!i-wpLk{96p^dBXKvo zWqr@N6X+68oJe*YrtT}g-<$cB(ushKcNzbfYAX;(I`AfIk6w`f8m^7(XP^)*rshns1;7D!B zI^sesG${atsD#UaH~besp1JB%TVXa(cx%nwtHz;{t~4l@;WiJfn;EpnB@f`Sd&GRFeCNVM$I8{Vq=KIu$q=eqG2 z*@=TQb4`htY^$>-RnR!?+>+Dtg;5?dS3Uun#8kdI5tzUm(xn4@mLs zRN$@;nyF&aA;Dp|Q4VmN%j1)~8=zIgYjV{_+i~4nP&V6NI?&SN@1UULHo|NPQNIZy zOu>jC|CJNJVLLLO(6sl1{s{es!kqQutAqt#h+V*G>&$o!v`BMp9_6Hnb~NW)zI$Ag zd%-$neC+%cduCT9HF_S@&V2^=nbea)!BqB2$V+>ELhu-5*KO*q4*KL*`7S3%!K6Xc zGE4j0+PvEha|apJqUZ-ILUE9A>FmAHyYRQ>vX`;N*RKy|Swg{-v5R+^YLw=77SBR1 z&t~f^Uyt!p7IvYWI&6{9w@x@^i!U|(wYacwq|Ul3vRp>{l%)a$MEUu4m_N75$~Ej?a0HC5GZA7r=vt|%jV{Y||s!|a};s5huQ8>-SK$A7Nt%-c7 zsHo}IvE4OIH^QTpFm+}xbylv}6&k+pL3S|>2WYD4_ab`ra(=&Q(OlQVKC>aOc~pO1 zFzfRz!MT`LfwHy^7#I0M=*|L#bbh_=wd68)95Q+Tw1FTX+r4&F-K+;<_{Na@l!sJ1%dj$gb6XPe|vsw&BRLOWiyrY)BKz4Z69}AWDpeSDu>}nc{53?-SOyhNP{zRlD@#7$^|k8KMZ~p{AyWuBm0` zZKuzkZCw=7Bvp}peu@6Z-T8VuI*;r?S_Q=Bc=~t8`<1mRSsVSvtvk0YzwD4<7b`1! z^W(usyt>Y;*J9f325mLBZZ&Q-@`?Qp6J3o^mni`y$4}{$>|faZSKDb9`yJkVbo1e^ z+dS*H*)?SC{*dZQFNeq#L!wl+gqBstE_i>dfBylCe|@?1YtAE=Pu0RWA2uxH92Xr33_MZh|J)qSg{h3?0?SX7Q+3+=g);= ztE7<%cqsZMZCzcdITqL2DwAx6RHzwE4F0NQC~4Si*W+ z2TdtE9zL7`>iVss>ZIL)bi>A4mmkZ2lxH_urYIlgnR+TsZ|3jrBS&`PtQSa|lfxvr z0?GrfK_Z?smF42ZlTSvT4v$4XK9BduMI_5fFQKz@BO4Qlc-VH}@;{&=o zjE>R5@|QaPEML2Jt^IMI4os&`d0PLT_-pWT&-oKg$ZL#v9JAqvXiEncks=L+JVURk zqDI%WcY5Zv0aRJkFLA77D!LUmxg@MY%ff2TmvIbejn0ZJeVo;I zo%W&*%zHe|tv@Lkk|clg=3M{f#8EpS=`*4;KGmGW9my@gewk^SUex;Qbq7HJGvBxZ zPz)MG>hvca$pGoW$&RO1y`byw51v2YANhkST{zn$7fwdbj|!my(Rc{Q835tH*{xVu zGr(=}Iuj&-SgpcOpM)+&VyBp@Co9y~nC(dVXsI-D^nlU=nQ6|*@40Vc$!mwmF=l4X zID?i3q<_fm^KpAnP+R|pMy7RQYgC<2&6wEt5(`S?pLnz&HV&(I{*V;w5~3igj`Vbu zFT0oGr9@LCd~)_@;fq%fXGCM^ET6QxbLFQqk%?JZhu%HrP2PqQmA3je_`juA!`=o4 zogp|0xJ)1$TCMtAjWS;$oA|A#jX2?=bb^R<@xay{JMvfm)^<=TANBBM&9AL2BW%qe zLY_G{JM@GOBqTL8HL;57P-b*^XhXmDT?iJ&Qxd4hd|uLybgIoG$BxOn@t>Jb;{jcn zm+gLHSkK^8d37&ez7(-H4qLd}d*X5nsEDnDFEjwdk8><7P1JAl<#6zF{+3gxpMBQQ zk`(ZE89DQ%#Fmgh$R`l^82~`0J(jK5yJrtAh0}n&vpB{&bo#X}4WvFeW_stHD$Sbh zbl>=fxHyr_ViYA(S_*_CXU<5FcYk+S>qp1E${8Qn zoo)Wv77(EExdN15l75&%GiZ`l21s8fy`?W9#Rt7JqY!wttpEuaK^=!t~d!KtXUU>+X&HQa9dp5 zjEY?*Lqgee*cmd)!$7!#R6o?DM`B|;F))S1l0rziu=9f6O#Rw;SaZDhB^dF0M~zb_ zR~SM;+!tyT{L$;x>(|5ke6lmW*U7D{8CH@Qi3tCnS+NlQ0U1eXVD!yUyYb)fywHf7 znYMqMk#XnL2xcD%bi0hgDI0RCz5=Z`u<_ZnsSa;47XcK5N~tcEZu~uIK&+G_wCSyu z&N8Jd&=9nnLLLaV0Vgtum?2%g-J?VP4B}U5Y$UX&ancXnyUBB8ZuRhhyC#-heNNweZU zPoN&u{%ek0q54r+ImdO&`QJUQ+Gf5AT#wv2L}lW$i(Dc_?3%puC8LX&jHA+)-AsJ zz{QI=@$VoqAnEDTmVBfGBj@tPrde2&&lnOw^Nkz!lA@VcCRfjei5`!@0(<^qVuT@8dAb5gcq} z4;`60;Xo0c`SS_>AJDMkgv^P_Q{boP^FUt4ZXB9waSrAU4ILJ=&klTGtgYCYlEg*w zdvNzd%996UG}NCEfW#&E?0>Wd_~@Bb4x3RRb(+?cPx;Tn12;gqfXaVBdGF~b?IDRF z{ZTD^{30WxSM}cZMlS3<;c6h+J(->il>>)7Qb_3Y{u1^Ai03KWgPexu5yv{L#icY! z8e0y+Rmz_1E9+&;OkHN1M3@sw-)-c`gSJ&LxD?_27Pe`<83;(BPVxjs2)506-?CO&-t9bpo4| z>9eMdHhl)pC6ESEXz`41r7~OMl530*3s&{+Z7#kwtC@)GC!UhNjW^n$%^MDx!M`de zPM*AIX7OM=aEWde!`YKw_gJlXmju23(5$n*)w!>W+xG_8GyHIW(TOhl&Qp)2-_6Q$ ze_Zxca|?bdR0&XI^(viC9gU7|1Iupicz{@#Qc=2KTAtZN*__x-yOs@ zKQqnx%>3=EtX5C!bTv9U7sS!}s}q=W`h-9`(#dGo6ou=aZgg=mT(F?a&Glaw&b$pd z-0Q>=7!HOgzJ>bQ+2WFSL*B;&FF7}qv1+DyKMWMf>pGQ_-- z;lD=xET7-8a9cmua>y0J0SnG@qOD{i3e;*mWy-@rU;UXtGl%1!?Pg}xjjhv|$%uLG z?feo8%|GGQL>hxn{PU!a%1;d=+>vbS*&6;27a*6)>+Gj(G|c&o1|-j_q2c8#SN2p$ z901hzcr5Cn$iCR06JPJyjCDsmYAds=4V)%UY$O@65J$Lw_Uy<7H~0qfmB_4ulKWBG zpMU}C$30dJP1Efi9Fo{|+`0D~DF$r{W=MCj?<&52$-@!F@tK)n7aHm}!CIXsF5*pD zh2WzFheUD5s)XOOa#l0pvoIU&wOahRQI~I$u$D zvF#2HKDqnhEiQYw65v{Yb{ygrIjR}k@d?YZQyS(K=j-b$a>>^tb$+HRb;Hese?biL z^Zk3vF)^h-4gLEVwG;iIAwE5?Yp79u2-{)i&Y6Ai@{tgB2$PCeBlfT3+S+>PP-n)P zhYC07njSlOQUz$|4pU{Qai`ZGl=Kp~F`94xqOU^#+xc1LR)2q?P9X@)*c0Log;?Yt z=)R0`E#~_};8bt{fZ!M(%gQA_sc#;}rkknzgkw!C*|UEtNtm@ForFXC$%Ldy>ALQ} zKlYZNBFHk2_;qF`=R*TZ0-*HG(JB4*O}sSzAc8@Fl&&uxQFs7tFhuiZ+TQXNkIj$U zvn#!rjH)4ND6w$aK|+{k!z>-{2O!Q|?ny?54~TB_(-|~Vyz6@u}Zed&Do z>i5~FW+ZZi;u3Bh5zCoo`IlC~Su|Z+zw=J+&MuV6N<;vN=iHgy>gLqPTVk5dbNKu=*` zcxvw~Js1W^RQTnK%$M!b_HTOre3rh;&jz?Dce$|6e`!wjqff2>bN^EW)DFm5(N6LH zM+J95)%3XB5@)YQij#aunhOlrtDjmi$q^f7Q73CV75z>1C2e%Sev|UoamHAN1hch> zCl@&_#ox(pw`Z(T#J;K&8Xh?etarkMbuoQEm*5h(1X?Va~k)!{JG%5x?NnDbM zcpQ8E%|vtgKfD7I<6>ble-+~dCE@_g51w7Mx^X>=7-t>)(#6;JZ(>B&98hbt7%&vm zf~9AzrVcKj;YE75zrCZQH?+jr+6?ydZn zQSjMMIiMczV|t(18TD!8K?WH3V4i)%Wq%|xawl5FpjO@~`MIDB-0}r$$Nn7r5~`kZ zg!#Qsz0VCFN|H(gPG52UqMp3H|G}e2AJoI+Ixyt6eiA-t?`+;g&XCiJ?}JedNLxb>s0)wxf%Mjy~0*J@L>*&n#HyG(1@P)$e;)ZfQ0nXA9QWl zshuQ^nJh3Rlv1d0KJDg@-nenZnNUA!Xvl|BY$5|9#71%WYMw0&zMK+g!KE51Jg_l4 zKHv+qNg-jtM#kza>V5w;ooD_u{eADjgK?}FGQ%>|kB(lkYsaY}$}V1eAq`B=yeYO0 z!ZSoq*2V2-3rRIX94!V63~BlK*ej@MI}e8`#1%s5(=@GJj)YY+iD0MFo9r$j>SPSn zHYdmh23p-Gy*O)W^!yEyFcB3XoVZw^W}068tKNw|ji~T@kL(#fSZCYr0U+JSll`X+&QN zZi_X6EK@_+KA9#hc;o#@S7lXJJ($wuL%6 zxd+xjYCT(WmwC;O_JjUEw%!CR=e+IzzY=B1GC~Wo&6F{gs3eMPVWjM9RARC(CDEc3 z8B5k7OAE4AmY5{8SxTZL6_sj)5QR2L^?#i+_p{9N`#;AV&vD=PP}lYSewOompYP>( zXy~1}X8{7pGz4{uh?+R11MJ7mjJvYy^PWB1+h@g$qcb>tAYmcf+TZfhSwOn}8AiQ# z+}_r0Q**L1p^p9G;$_pq+xn(8XPksmar)QmHZb&U3ll=f_Y!TsDaZe8l%lUAb9Ct?Ny_j6uTo59*dPhG&kr zPMa6s*f7jw4>^X^g_4E9XWM`4?n8g(lDCtR{HD(z^z9=5_Ltuy!iG^DoJ)BfM-zOT z{gqf!A^M*vv(xx&35-nW360N0*Bc(SSCY1fA-uZTJ>qc)&6MU9CZl#UBVVq6{Kw() zE;ChmyYg>^70eHq@O$#r?=%l}vj&1B!wPUpmg&U87|sNmMY|O%)VPL6UE-1!Qw%y> zXeav@U8t^JPrH8L+Q_iFCrtBNWHwX(gL6^H@O*B$2(=UouC352F(BR}a({e7Uoccq z%#lgN@^rye6c}5~=ol}5B8KHa)Tzn6@my=kO$vTf#NnWwnFMR!4 zd_&*``ked^3i;ZAY@g5 zABduYTC833rrPQYmmbw!A942VS&N&6Bse`=!fgWYMR`xMuy5gu(dYQ@8UAhjO53F? zSI)RP?ufUWZD%`R8W!Sa#Mq4Qm_4}BUN(VN;mXI%V^o&d-tlXSt0FCvX zbEPTDqajE#ac;VMv<@``qgp8Ui&L6o1GNA5aBYPScEZrl6qVOD*t_LZ+)HQ&??na^ z!RLdlxNUd#+j_D$*?d1}{d6E@NPSn%pupIVK!Ou?wmELx!xSnqtO#kDfsdu+VIzEb z7b>=Vb?zU$lcXR>p`yulvIqPnW~<2biekl zUAx4Toy&2iQ?om(9vg3*sNP;(owAyG=uG4+laTarNP`$fP{p9?r0Ys3{(SkjN7^%g z+0VhWuet;9iXd&crDJ)p1E!4FOK9zF_TPy0T;^!-7voa&zJlWFV_V}DIks!;? zYBkr%o`a5u^yA~{^XL21k}fsHy44;&(5WWRs3aiY-^SkPGGaulqYohV6rno&$?rY; zWFV)WaGMB4)l}E$Z{tk_x^y}+)8h196v0P^v4mqyR>?OCpZ1cofw&ls$Jo%~Bc&CI zj}3`-7ulV>rLZvZzco@hvB6Xa!Xe~M5h?n6zR|4wIQHJI0S;<#O|g)N$D*raQ~V41j$EHH8&-aj`IN=bYD zvH^A)ojbSUMgiV{gE{TvGeCt~-`Z(x{>M|NPQm}GJrZbT?aO9a`@~@q zW{MD=Wk>`VoN`s)>;UN2_%lP4bw8VD9e!O=D}!Ya@+oBbaKeSg#2oo?<}I)>xDSGe z)ILJ_F{jZ{xQPyAUofe<2WcbA&7ttt#sdcWbn4%2np`j+;BS1O-g-(0F#&zCR13*GHajc<>cfXXeirN0o&*u?roxwzV8_e3eBRx{owWSKIdlmc6?ZX(eIoI zI!7PZXePZIH>Cp}dvmjd{??+EIOoC)C7)54k_?Z3c>V+o3eukr#0zh%Vpy$!<@`f= zmXVtq7TITkOUPm1oEta)cI*hN%0I@<&b|@%Re;7ES5# zwBMa*RAavMcVP?JU*^1Alhh%8P!3=fQS-ez|BKa(oZa-(>>R00_Wul`mG05tsFbq_ zB(`96VfqMP`tPWslkYd3dp~0yTjLVug0BRf)c#;I3ptw4%zIXS^;W}B*z(6 zhktBq*)H_jwL{M3vpl0cOVqBqo);+*suV``njO08hlYHq^`L*VUFo%`AZnT7E6DdU zr`>0kGO4qF|Ma|=L~p8ntzl%g71x7AfDvhqSgn6SrCe6(#ux~(Eys>bFAz=2j0&#D zLQry+WME=c+yz^S@?-DzVnPA(_xg`+u+HR)fPH#Cq2x*nR0B$wKjD=p#JnY|S8qeo zhpF#&zRW_1*FUZu@6x|=zN^RZkPo$CHN{Y``8SeN3*sh%qjd~bV8(#z(>fNTjp|;p zjNz>)+ekZE+STw`6_lZbpNmyPyH#$(Z&H&?ddQ4|22~#gjw|qL^hBE|m&4a|uZGc@ zLpaF=`os%(_m8g!RV<|r?5n*-@s*jb>|U?|2dv9v)d3K1cO~9)QHm>L5<%EOv!SVr zd>Ld&EQ~NK;QI-eVTT4h4`zb&*keNb#^WBuo`-gGa-e?7 z{X;bFFGCu?>wRtuf-Su#mMKXL181jb@3P9BwP*30qwj~?+u3>3&r%w4C^*1pUSxwF zOEgo`lhC`(T&{H6j{1EAZl-cC(6F?AmU<+;q?j+{M~_X>oV8*F8HS<_B2NSW+IQJ< z@-Rj>@hSAEX#KoGz!TWU>h579o}0A0zCw>V3N-$OKn&vI@2L37**_+y{ARav!^vZe z{tR=*9_k8p#VE3wm!>3EUY!+Wt)imB!nivwwB?!haSXi4 z7k(5|Lj~KK$(0ZA9OZ&u=U@UF>Bgx~nYpBW*{*iYYzpVZ0*}vQ$*%$%Sfd*vI9MwCSv^Zahk< z`?#kdz;EW_E$Q^*!cRU{ahH?Jl%t8${T#1u?nM>#$+)lk3wzE#$H{o?^g zpA{B%t0^x`rWzmbqs=Z5f`U-`xeor~C{Z4|gO@0Fymy{G(*#jornH~881h&s^qvY@5`MSX)TG8KpO3@23t%||KS1hpr-=>buD!g&J zcT4<|N5g4hyHLA~AKQKO*hh~u2G*ri96Devb~g+({BA3OGNL|7K6oYZq7 z{yTm8CoVWRy9)4Q$sgm0&H8Fdt$XV1LY^|f@$6*c`RKq;G7_LjS>#`3YhpFv)~6=a zAmVDnvF#Ywi3cdI-WU{%Mv?NJhDQARK|ZNCBAJLdhPjD#3B3}ry|i>HGktQePS$Qb zxFL9ZFW<2&8Ikc)LIb%*?(Y$tT>q)o;}&Uq&D*rGm^DiSQt|y~HRDVgOhe{nIx}H~ z+_-(3V?*Ja$&^&TwD`5nsbMo<*PuQJc{$~CHNFJDDv-rDAHq%AF~p?#AOhgiLx(;A zsS|$6CVZ@U*H3oYyJz=(vRHNK6 zJLr-T1SfJr(u^6dzgk)8=yz{c`6St(#SZH4z!pbjCTJA+g)ecaOTUHXGT@Nl&ZeiPUjdcqw((|s}H`dcGO>OIDOTPN4y9O{!^!ied> z!QTh%y)YruP(Z6A*S|&BRrfiw`h3{%!@3qCJ;Iv>#?WtewQ}aD?pT*l zgHr~cDvSU+LoC~j1q8}JnuqE!yqmyt1emhl5^tP^@{~Z_vUm%~EzsmNP4DdMYkE+O zNQv404;8oYSY!i|r8|4xJQDK~Qd3(&^@n`l5}l3FZqW#?CF|3_!aKP*5mPxJED+&{ z*l42c@I4g^;0b%D1s(7`_yg5Hf-GFYTNA8!S33s*pa7Ep*!dM%cKBiY81Ye&HijP4 z0|O4_2YZZ~Nvmd5-WIlgxvZS*fFbkj%Ti%zLG72TkC1u2kg6y)-w_U63 zSFCvW^MNBq`kGx#H;BPLhNwPJE*w+a0Io8;uKA@gIID2rif8%)1p^U?XRk#|ul~T- zC&I#7vLhIt^r*~*UF)iUrBMVC~6Fj=Tr-yr~K)~Mc`rs@kw>t$-v3y;!UE+CZ+Q^ztgiZSN+lOUM z3>Ji`q+iWHM!zUO(#0h!P}S0WZk03bG4F; zuAHEZDVYeP8KehRZsZ1FMCwb}F^r|5}Aw2Xs<%wKoy6)u*gBSM!ofU(%gE0cTwIS#aA3$nhepzCr|b-8s)lf z9gFY02@I*9z{~8&wc0*r(A(O&2)m@Y-P@f@8EDa;HEA}j`}?JrE)9KSQ(EcOo;Lx- zBGCB@M|I%AoqXWqy?^~U-(a1;sZLu645w}%JYOKzp*TX%PG4u%WOK9oaMj1cThQm$ub zRd~ZJK<7lxiple~!JQ}%w`|Jixlm(6fEtPK5FC3dyu#Hp7J324307;zF$y>w*`yNp z|3c52u48&;6fV%p&dj_+bu|9==CIKG$B)|)saa)^>A43CT?7Xh7T|O31F{QPqw!aDt;1vMjDBu!~>OrGx&qS>64DiR;kZ|RXan+sMO6=vRk`m_VMwLGbV zi_(2KyWo%eSADnfEYmXG@JYd!JZhnJ{+r3woXV^q$Oplu8=J6F==sk#^JYOxAdL{2 zIHqyk{VPA3Iuj&z2?UOsvAy1fel--|2PtM9b;R=@S7#uKq?)N-eHYgwms4X_y5%@>8VmTTjuJl| z4kID`2D=r|*i$sBG7_IU@9e|6nY}wOr|KCp@Q)i0wWrlPyuGEee0KQmW)=BdF+I{L2l{UL@jFI==pNKjuK7cTr_^X+8VsHl+DwzXky*7cj$rd8^tZynVG z$gW4b=4+5g`u~~BT9E)0d!7mpHEhP$b8%i=q>u%l*iLZ?Y}nzQMX<{FseWhTysdkk z1t8r1LAYfSlEBuleb<*s;hB$x8)0U?V5OD5`y5-dt zrB@cbelpLbN7V1uf)wojFf4_ovtOn zwGMXrXk=5d5_p9{;r*19DW%QQZpqf?@r0#x|E=%g?gyrx|1t4RoTt0i%{`IEbp;0M z&$9k>9SA$3*S9r=#e#iX7b*;=)t16vfH@vz-cMrzHWeUw@`z+pBO5)Rkwk65;qLfo z77O&`fa>{rYz%THZ5I^_pQ1 zw-{9+_$t;(qbJ2(i;fP3Ny7r9o>}I8Ic)dsTa75G?C^41RvMgK38K!-W!p=7b;WTQNW7wUa1$FuES0PhwD1?Ssj- z2Gs+`PI(oie{G3vS8GmD7`^qm4`C63bB&xhG1cI?_y3yn&O6asF+!Qa5GWpJtUf|b zqtU{zgJS!uEdih3cBB7-(p? z<>0}NkTg=?jmb2WgjEnHmhM6tH3k%!8&FrM@DDG9(Y{aBd|(WiY&5zdv_a5!nPc2ZIx*#l+Du8@JMaT-W`OCq7Wr$n)&qQ%YQ*hE@c!w%hfo#0%52w zIjVb5+kAD_A|80k_gRERDZYBdB`sL#+uq4k2dil=sdOg~<=Ctd+_rDuzO`E%X;1?d z?zYo+>Jg+i0`WtT?G;jZeXZ{hy}F^%pr<|djeq>~>6kZiElEwv$=5<%_ww#;w3FOy z97ZRzD=IJD<#+`%qoTj>KJ(xlhUt`}>C@-Tv9-1Ck{wo@e5(~FMpBZ+plD%E5X#4q z4D6TvS(s4}qIQNwUHUM2{y6Ea{`_;x)bk#?F-gs?Z)-PENK$8RC>e%>hWlonmK^^58#9d&Fk*_QG7oV-_$RVu zNFLq=o8F~|kJ1MnCDHCS^q8zThc|n5lZ`U#F0X!k;?h;PCat*e_(F?3OGsIWoE`Bw zdRMP0-P={V=Vv}>a;C(yuwXLme?~N1W8<@1t<~nUXZ2F&q!xc}r>?F{k36$T_|Z_@E=NY% z|KzLhX=1$MnfN{)NZ0a{VINoN<%?bE6dA+PGnQN#4xdt94hL~Bltaa9DJiJ91<{AA zQ3}g&h?OVMviNu~^cC%^$Yj6?Ph7arn&;#fAK&PFtd#F6Y2`Eglz;k+Pe$bK&!0Yt z>n`c&9VgSX3(xWF_j#}-&VFA`uZPNj{j+?MA_3x9BrYJZz`Y;d;Ru7%E{t6Y>#4&E zsNDhnBX<145@MZ-LI$t`q2|i?#6m6`3T~M2Mp_3jh-bzFuT_0m7?2(+mbIAh02{gt_fg89eA1veettcem#D-NTl zZ$hXX0bv+#j?DI=2$jA-M$5sbM}BH#jRx-*+Ws|K7$Hzv$ICQ)p{0^@hr#`u8sZ9F9q_JN)|XH<80mS{QNFR3xvaZ z)AiEaCJIOy7cZ)eokExI(Cn6`uG)^192FM^o*#@%mi;0uDC()SpO+tY&8eA>qm7KS z-(J{t3oWz`RWsXoP7MTyZH%r4S$QhEQLxYW*t&Ai7X2HYe1Qp1K(^x`0uBBnSEn2c zAL{%kSC2-P;5{QVR)Ml%qP}$v8nnxhF)lTx^w~oWcx&OQFAg*%fmdzJ)&umhlG@7i z2^_NTr$%lH!RQotIle#sreDs22h(fk&YpcPr3Q+d`K(z1`lrp>>U(-3t%US%QXYHy z^wzIEzkOQ)_AaI{z(f|Ua40?W*r=o9UG!}|SYBULjO2>_3rep9~~w z1CQL~r!2d0m3G_ z*igXkut1dgeH^4hum$r-4->n=yVOSJnTCMVlXksBw`>onf%&iq2t>}79R)(cG;no0 zN8hbmo2C4go|dNDavfh4UodfXkgZ3%F1wP}4&i{JvO4m~tJz&80?y0~IQjmO`HwUm z-~{UWHJvs#wWLDAx=zlPC<&+=FjHi5!StTvyeYgO4Aw_|yhRSvwz-4Xa=445kYokI zWo_Ctf!J<{dJZ$}YU}DGmygR6W)Kc9K65XhriegWXGWifS0-MeLgpf>FA*Am0RJFm zygxSFS`u-sMqlRclZ_9u2W`ZcX$ML7Fsyw#u1kCHKn@s0>z_f2MRCC)0YB?h;R=8j zlLm0j4PRchK*36^VoRt9o52&Ida_pQe=`&7Ch1t07Jc}jCQm-zs~cmg#U?ArjTf6A zI7rk!s1leY{Qce(x0yj+67c|Q;GHiz zU2mv^;x!EaT7DWgHB$oMaPzQ9N@8ToNhT~4rWs<;Cd_UW>@2}^mo6pq1@4;#4foW> zj8c4P3D@(12gLz*z-3&fA)?MnZ`7S1A?_BNPian|LBcN^EXZEVv#%SaO%Yo-0=8%)o+d_x{ zf5Dfq6?I{RBVZEsw?x&6TA3joFKzFwXARd{9iuCm~{w6(*_sZ513$S~(` z2yVu29XoYuKXf#QoZKvnx-t-k^FmqMciy#K_g_K#wWEF+<0@IvP!B%C`H`SNxuvVC z{orQ6#i(=9Z`%pXNQ}@S7=zCuZrIMin@`JNWqTJrv^{g?v|!F6Lk;mB6TWe2X)BtA zs6NSYOe*}?TH>F9v&R?E8yRy+)E#HaNOUswHWoTq%k7d&FrP`pHL$HNH473MjLoo)?Q*H)xwo4CTrRszmEy~r?)f+)O z*?aP_vja2#K4Ni4LT~_foycv5v`i5FL%}DPj(BWX4RH;2H+&>%sURn9K`TbJ+Y>4g z?U^tNOyaqtI9|apcXNpFFaJJ7A|rda=Kvkg`67dCxo3d5DIF%N+Diu4?GM-j4-}pm z(mZ--6UG}E9QmrMsxmw|KmE#*X~TvNC7*GdxJ8P494Nk&HT((OJ(-OZ(auK<6qp8b zk=XM><~V^YoGFdw;1!wxcWZHL<+9jc%m{H0~m2s*x$Y1V?hn~Jnq^jp*{)V#cr7OaiG3BuJMJFh8k z{N-H8KN=W_$Zfg6u3x`y&Sxb{JR;TwA3Nr4eq23TXDJ`$qItjDMaMe;t4it$`Xe zT~6nvD}EOA2RbJ(K8{4rx>NMa)42I4i>SAITv!Q#O+=O~wyRBEvj?}pi2w!v`-Wrp z(SGwRI5c|3y4OJ{-~FsFaXs8MG63UE3P4;wlp|97^u^2`SdjY9kE(#5BFtaLMKg_@ zK_-wda99cR1w~@`{6_dfi`uYwL}LcFj;IuV@2D^&KCmw4;k7N`n zHYZ%Mw44#0dT~8mM@0(hJ<=|*i42D+#_?+XD`KIlx7Zf~ztT=1t&t&J)^2-`QEFXp z@{;`8cH7-{_*VsbB8U#$e%nA6_zgSAHR_oRo%(ks(3A&a=XiZn{ZQKBqPK6yf5>FT z_&cY9Sg^<_+d&y_Wp6$&IyMoreeWj#M=$w7NM+=E0d&ZoYq1VSf>25#%*A^{*d1hI z@Sps8zhhQ;n>~)B-8K>(?Xi-N*g>J}Io0#7=48RcITxhnpIYq&#|Ku7sG5jq)SbQ% z#RDP2&CmMo7`O@4q%BPoJc6~=E(>?F2o7r-?WMZkxasH_?9X-q(KD`oncrdOy=8xl z2($2CrZ{}EH&IUsFs&iVy)roCG&ie9Pgqgrxp(gPR(!X-Hr$u7TOv&v0+72nBmDr^ zBbo6VVfrYN@zQFJXa)OW4h!8M9tQM_cUkQUS+W>(KNRl$- zIc~lmwbDg#BVZDYeyg+17^O`=!Z+fUNdn@UV@31x36X^z<+GgqRF6lx$@8$VP@%va z(z==+hi_yAE3ttRd70mbF$ zE1$o2x3z4$BI|t=?ciUy5qaqzNiY8Vi8rwjTSPEkz3sXk#-6x#trLG>#>7R>`APKA z)bZ_LWFPfHWij)Zm$LnF2i4502TXL){BgH2h-<<`#p^2~uOVKJ%a^AGCdWV)Mtz3i-?F zn#zW`5H7?_X}pz{g*XZ{v0s!Z9Lg5@VTjs=8b#keC+jffKgHsfCoaH;vwDY^4Vh-`)YU3fhBh+zDK}P2Qd^!E8>`Dro4vlTXDUNu=5&OLIasdE5F-H^^ca zPDTt6F*2u`U@-+-AvjPu3jhdBL&hA82St>1zA_xAHLw<$$VAl+dEBL}j+APRxNq-& z5w$sU)UC|%YRl*@FiqI09aTrEJ7G{BsA)ueAHYUlE)6a6+BW*vfHu<;|acuD>0~EQWHcmChdHbFX>@D_exP17njPEp+?#x0WthQWRLshxG*!CZyo^E{>H25~d7a z%I-xb)+5ri01qSlkjMqJE?DPqy-WDg@fxj3&M(t18od$gh~apmSztOqCeTy2S*eQ# zVKLX32%kuFdiy7DF6i@~dol9a%YX?RtsPpNQsburmrb+K*Np>0sLoNcXut+QiVC%D$?dE3q`h5x2_c(+$TD#S2t%)6QkpBH$?Xb^#<41)In2gJ%&T3X2HvD|XWOQO%XwcW>IfyV3NYM=Jf$`K4>e`K{jH2!Ce(!@7g_W=!AP?nck%y<3nC}A!Kvv*_Xu+-Ue{I+bVG%05y zpoNo;lAnFM4jrDBe4hy4_O(u*VJ0S08PJE)ii=?@c$!?51OcwPUs}-ik3ZY4@SoD> zpo)7`43%r|-oLw-#$ifoXTpCK`3WU71cGt=O+=!2QEa7>3LSlQ$KT!&YgT92#=3Q+ zrW%y%{)jpaLJ5Xl0zZopGUX7b@Nq0^&IUy8+_|&BV*MN2_+foR?boY(0N90k~djlztShl?GeDsJeIe&YQ)1hP-@y)A2K5sCUMuh$u7zfG9*pVYQ zr>OR#d;;&>3{^?;Lv3tUtZ8FNI~25SjvqJT+SRo?$Mg(R-Izr0{4Vy#qT*uFAzjqi zNQiWzy$YyR>$LEkd6Opjrzuy@%dvNGAYb{x@YD(OT$%5IFOK977C3D_w%QHZG=)eg zFPSTVIhIhruufU0(|u{_5d3SwfuggDC*O>x=Wwc6sL`?G5!1ncx?K2ZG;8+kB~Ed} zMwhC!Y4hgI4@T?y;#x3d*f3-da~!|c%&YzSRSHaCCkC(Pyfs!c@(QwAFGcUk%gZY@ zEy^1H2Q?vSeL)!uqOmlmAA^g_d$zFcOL`v{w{FP>)m7CxrKKZ7d4P1^+{3`gt*dYG zS-nF;9pVqE=67jRfWZPgzh?3MNt`#Uz7AtVAX%ojZrQAEGir2~u3b5ZZ&xLt0l*P+ zf7<%xsdqWiSpqB=LH~@$$|K3}W(-6cWY!Uf%O_53&T|E{rU9$-IG0^eaM9psX1PZ!DL;!YNq@G ztkqYedj4jn<^bVanAxi|b1N&?#cq2UyN46lPCi*q;kX&DVi=V5*7)n!z2(zfSSnPGnuXw90H-jgCqKa*6t(A0J%6Mcq`dy`rS-6 zJgE0E=30&CpFcwkLOW`c_a`hWI!%kxxp_%C#D*JpoWQZUVE*#FXUwfgOF^jz;}9o$ zfv97KYvwin`LTo!l&{{|GPzzUoF^$odhA*!mEAO|fg|3=-29R=4b!f@8}rH9G?W@_xSFMh^W!S{qD* z6U+U(s>3<>CwJ3=50~P6g;&XKL;2uHPl7|^7s2V`#7WQ5`T$x z2+UHvpiRx^&l$tE0oA{EX{ldr`8KdVnNb-jkFgPuUl;$CAll)2uG}~_oPId{U-|7vlSs!G%;yrpF##YScDAd(OzuUz0xUV#WW1uHPFnxldvxS z$))}>;^XGdO>(mfKE(A6fD+NS)9CK)4tFX0v`WIe(#>kRfI@yElRKlG!9RJq`CDOe z-1_q17fmxaL+Y!t6pxg@Lu)I}W8fk_u;AueoYWIHQE!EX+?5h77@U)@L@^Sy9 z9uM?SF2>NME4DI~K0iqqui8)|UebbYnw;$ZpS)~^n~yw)zaPeb|39zx9Td9%=YQL> zcSMVp3ibc{hwq2n^)*)2pOk4oo!T1b$23O-V2PmPIy=70%#c)vlBf$+_a5N+e_x$wXPY4Cr!48We&*>KLH%%LcddIJ=OYirk`0Wdp3bW~bvHwA8CJIz6>&PB!S> z<*2B!fW%Cc{STe^nWB{Wc@u>w0q`DNWb*peEAtC8oi}zP@1|*!;rC+RgR)ZG zP`2FbJqGY;;HT>)) z3Z4eA=9k#5}8H>d>LlA$6ECp_* z{bI|h*4G|T8lvDjIc&Od5cu;zF4XU@2Y3xU3f1$azi~m4+nS1657Vlr(?C)!yehDh zcc6{WFYKGzlPNhlL62MLg7>S#mVb7AZRi5;OsLKH8)v+mG#m~#rui}}p%3^oqiW*m zsS?b@%u^7;)+*is{jlC2FyO%J=|q>I8~uTbj*>{&%)3;=X?N*`lbV%ZU5ESSF@I{P%oJkf3UIe-jTRM*2!^@SVw{cwhEiRAmRK1o;;cG< zx^=O&LgERUg=3l6HmdkWNZ1EM*o>9*Ja^%C9zPHQulM;96H#4x)u!5B4`2}~NrVym zMtgoTWBYUJi{fS=&w>&o4wlmBt!wh{Q$wdo2Svky&NPTLYQ!^L)M#fg244)QEr9sY zWzS|5m81FL)(yWR{;F zQSkztKXOq@`%fE82_2!W(%>S631%TuvQ4#%<%QWyW?ra6*F~Ae+@+a-G86?e3*lu; z3>I%jO7iFzEQ_ChYDQfx?z+^~iS>BMlRHX@wl?-y6g(!v1nyTgRrO{F2PA88DG(h4 zLo~=bC)CYR=wQ(Lr1a;0?YB#Dr>_>8Gfm7X#4(#sO7M@2*~$J6by-1$P0oonJC6?G z9z2{xeKqEc64*#GrrqlY2Z!c$V>|)1MZEhkoUR|POKYH3b}VT@w)9gN0~VC<#8gT{ zZ{Ey%t6xeLZ&C46hn53DNhvJ9qcnS37x3TLf}GqN$4^##wSLHF5_bCB3l?+d9?b}j zi6wGZq%vGJ93#e>lZBhWo|ZlU?!ZEnSzq%C8>+XhT8;t}Z}0GmBh&lbBce))SBqLt zv-RvI#_neB_-!z=1|1DZaS1Zr*dBGC2=!QvAk|_K&}_yl5+>-ipR^TCCcBp z`s#TQwVev783aJPp?c2TJG#KF6`V9_!bPhTv{KZW$h1g8^(ODrx$xtQn;L&-A$v&b zqc^v8$Am{3O=udVt^{guuDgpQSY%uxn*{DQ(p2om$K@Y)q)z}Ho%>DvculMgS*=4u zh;7kMcywZ0l-Uffg~|s%v(T-F*Z#<`Rzh}zJQ-4qJF8*1#=x!)Ev64PE3AGjI=7_N zi0d-cJPGy`e{k`V)>7==zI`(Y8mRUsM&fIf-r8=eZ6^L8a2t?j-L1NdpV&R|T%`Np za(Ia%Ujz-i+Ds_O1BkL z<=20o(m!sP-qdS>5Fwd<(VkhhDGl$430JeP*H*n)W|*MYp(RryaYd8i20dHb{A)0} zilTBBh_60FqisM+onHjQ%s^{!obik}Cuf+PWK8%tJNt}r;3a0oIjLWPg^iDjW1Gaj zuy;5Y97FDGXoX@Q$ca<^9-hSFEK$0Gq#5zfg+3rm?~3_QGmSlJj*s+J~Rjy4HY!1ZhDC&VzOKgH7hQz`gd8B z@AXvqtMvmmEu)YzuCB(spSq3-i~^y~iQ^@M*F}c&85tCK*38Ei=jexK-^MYGNJJrl zO^J^fyh~0>hQ~5PZE+QVcO%Kl3l;=tyxxTU4al{d*?IVDIDC0S9pH5A{GsaIKQmeJ zpg~qT*yPsWHO|jUNaxmpRv;EFkh3bEfG#7_5QZM*4HeJhaJ@r|5rMZUdebhA`C#8v z?ZBES&~2bGT2~lCL(MGsRnkkr`NysJ(W2V;inL+;8@Jbn5adu7GFexJ*s7BHGq{A5 z!w~ocK16YL*d~A><${f`J4#3-AhzUvs`Yo}Na3g{ckMnc&mfNo6}3BS;-`gY!G^)c ze`stp%S@7riG2QR_wE)Sztq*`4VzF{SjcMl4|z+(+Y})c<~k++yC@yieBiDo2{qfN zp8t^Z=~BWY?}rzha|$j1M~kVVaC%6nk*oo_6Y+(*r22~jMuJ3<0tiq6$v6NI1+K+u z4YjhjZz(yFmFHDMSMUQK#^wp{07+{hD z;IF3>3le#;idAh|uZ&33=r^}1y&<{)%De6)mHRZk_XMUBG-UnnP@=~EOH!SzQ5FI_!~J@Xw=Yt@_O;u zGSu8+)bW||D`x*PnxzNCpwySUdt~=^cB0A0xS5ifM8?~vi6rD@-R}DFl8iFBfoC7u z%IKP!6ajF?ix(^PW1&q7KSE)w`~=e|=nRJwH*QwKpsN_hfokfN$4d-_MF^qSUnN`? zU55@^FrQs@ZZ+v5QFB`(Nl3K&*KT{IG)}3g&b;ToB4%$NUB6LA2qT3y^QK;D4YoGC z?8Ga5d93Sv2J<^9^LkyJe>3TH&Jsh>zk!wp1_g=4nGfZKp^b#ieAWXm+r@Q|#P0@h>Kq@##>GixsnsSXy0Y!!zCLP9Q5xfn98eJMz?+qi{-;3d0A3V0Bz6V_FoYm9PFje%7I*ZeJ;19^ zg4I5q_9;NT&=TWW%G))yF&$H{KuG6P0zVRbeNRd%ZoAOYhvldsCx?|oIIvicFpc_z zK}Frg>JyZVs4jFEwTSbR#EKE}Ah(#KV=+eQai#YAqLk(^87ng&ArIRww%ALo93E>e zn|G`rBV*sO_`~*^eB2%b2mXM#rz2%}=+!p7X6VP{3Y8g9BQlNrj*aS9T(Z|a;XojE zO^b7#@m_waGNF7!IEqDCjt7Rn)t7%A0{4~W5a5Yy8PoHfEQ?_GT;&buoiHhrwkDFO za_RA@4Q*EENZzXqWHtUgM(P}6+3O}Nn6gOQCV72S54?_Xv|UhgDkuLDe=Rzc@rABc z;P2Q(Erf8x)0JS2fK>>rnX<@fi!J8$1?NSrJpM;`yn|zOh&X|>$*m@SB(bqCmgL4a zR9#Z6QYqn764y#R#5+ULgV>Qhk@WOUA9ABw;gL4F^S05F1rlDwp~e$J2WCF6t0I_dNn z60HTIN>Dt%64d1L(u`fLz2xt7WQyX~;Y zOhV&=7NpEYjJo&+1%$hagV^G*~WlNhdwW8V+eG`nBe%i0H2yfaB}v2Vwx>7@>T`J!^m1>bYmmi zN+21rBVw#A-g`kN`%2P7+TuaXbswamO{0i>!EWi&33?m;-=oC6H&+=u^xeuvtJ728 zwJvl&i~bl^y-eT+#C`QCUHP051PqB=n0ILE+j*z$z0Li~aXG}}>t(Aw2?SM`Bh6sV zKy`%RmNsWa zJ2FmUoBDfFiAcdAZV4RmbV=wOi+rwdns7P1dT+ubr=VQ2V#QtR^ZQkr!*Mra2=Ga4 zN1)sBbf~s;fWYNEiy*!A!LYCJ7i)SJe~8#f#BSx96I=cWz4Pb;TM` z7~%0CoRCD(b))qDbynz1?VyO;#!S2F&C>eS2Yx+`8MEm4ot&Lr;*iCe6NM}M0BVLn z0>wbxc@{$HL6vLec4+Zh#>`~8s9~MRK?^|8c7Ci)oQD=&VgBWqghxdeXnWy43SW$B zwQN}D&c`B>ARIRyW^(!xUOzj+Z)fQ2InwdqJO;uW>bPwx~*vj1F zw&j&=dqU*@CnnB0acaMnZD)^8G>2d+eq3%LHAe9yIdV}^BiT8Q$4!y92G8Jkpf}&D z$H!>J*mX=0k89k`%>L<)zDl%ja`6e6&eXkPgJ2OV4p>)ZX~pYr?%h!R#Ju>Q0oi zh&3j;x5tLlos0m;rgE*&u3J=uza{|yE)GmF zAjAcFLF;E%+S-02#b&da%yE<48U03?rFDQ?EZC|!T9JU1M?2dd9t&1X*Jj)sJUq*SFW8ictr9kH_1n}>C2 zrKt*&>5aoQ6zg4GRTV*s3k+an$J18CDlUU<1r$8CxjxtV&BM(wF=h9?`C=r06C{Yr z_a02mvl>JCVSvv`Vl#h!l}}Kvr{#&snjcROCGdf96n{_&Uc%t(ZGVDeOclkQ@GQ>r zW?Dm^_S-o-ATC@_zjOOGWJVwA`Iqo5hK@|oO4*4Cg6p<_s#a2n7ZILy`aP$ z9tB`Z?+!bLwb{i7FU}a(O`v8Tz;k29!Q3TKL1TKHoO4KOJoYeo(rJ@(mqi^dP04%m z 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 literal 0 HcmV?d00001 diff --git a/docs/public/ef-logo-dark.svg b/docs/public/assets/ef-logo-dark.svg similarity index 100% rename from docs/public/ef-logo-dark.svg rename to docs/public/assets/ef-logo-dark.svg diff --git a/docs/public/ef-logo.svg b/docs/public/assets/ef-logo.svg similarity index 100% rename from docs/public/ef-logo.svg rename to docs/public/assets/ef-logo.svg diff --git a/w3vm/example_test.go b/w3vm/example_test.go index f0be1dc6..58b2e6c5 100644 --- a/w3vm/example_test.go +++ b/w3vm/example_test.go @@ -3,6 +3,8 @@ package w3vm_test import ( "fmt" "math/big" + "os" + "testing" "time" "github.com/ethereum/go-ethereum/common" @@ -15,6 +17,7 @@ import ( "github.com/lmittmann/w3/module/eth" "github.com/lmittmann/w3/w3types" "github.com/lmittmann/w3/w3vm" + "github.com/lmittmann/w3/w3vm/hooks" ) var ( @@ -273,6 +276,35 @@ func ExampleVM_prankZeroAddress() { // Received 13365.401185473565028721 ETH from zero address } +// Trace calls (and opcodes) of a transaction. +func ExampleVM_traceCalls() { + txHash := w3.H("0xc0679fedfe8d7c376d599cbab03de7b527347a3d135d7d8d698047f34a6611f8") + + var ( + tx *types.Transaction + receipt *types.Receipt + ) + if err := client.Call( + eth.Tx(txHash).Returns(&tx), + eth.TxReceipt(txHash).Returns(&receipt), + ); err != nil { + // ... + } + + vm, err := w3vm.New( + w3vm.WithFork(client, receipt.BlockNumber), + ) + if err != nil { + // ... + } + + callTracer := hooks.NewCallTracer(os.Stdout, &hooks.CallTracerOptions{ + ShowStaticcall: true, + DecodeABI: true, + }) + vm.ApplyTx(tx, callTracer) +} + // Trace a message execution to obtain the access list. func ExampleVM_traceAccessList() { txHash := w3.H("0xbb4b3fc2b746877dce70862850602f1d19bd890ab4db47e6b7ee1da1fe578a0d") @@ -300,10 +332,9 @@ func ExampleVM_traceAccessList() { // ... } - // setup access list hook + // setup access list tracer signer := types.MakeSigner(params.MainnetChainConfig, header.Number, header.Time) from, _ := signer.Sender(tx) - accessListTracer := logger.NewAccessListTracer( nil, from, *tx.To(), @@ -332,10 +363,10 @@ func ExampleVM_traceBlock() { // ... } - var ops [256]uint64 + var opCount [256]uint64 tracer := &tracing.Hooks{ OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { - ops[op]++ + opCount[op]++ }, } @@ -343,9 +374,89 @@ func ExampleVM_traceBlock() { vm.ApplyTx(tx, tracer) } - for op, count := range ops { + for op, count := range opCount { if count > 0 { fmt.Printf("0x%02x %-14s %d\n", op, gethVm.OpCode(op), count) } } } + +func TestWETHDeposit(t *testing.T) { + // setup VM + vm, _ := w3vm.New( + w3vm.WithState(w3types.State{ + addrWETH: {Code: codeWETH}, + addrA: {Balance: w3.I("1 ether")}, + }), + ) + + // pre check + var wethBalanceBefore *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceBefore); err != nil { + t.Fatal(err) + } + if wethBalanceBefore.Sign() != 0 { + t.Fatal("Invalid WETH balance: want 0") + } + + // deposit (via fallback) + if _, err := vm.Apply(&w3types.Message{ + From: addrA, + To: &addrWETH, + Value: w3.I("1 ether"), + }); err != nil { + t.Fatalf("Deposit failed: %v", err) + } + + // post check + var wethBalanceAfter *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceAfter); err != nil { + t.Fatal(err) + } + if w3.I("1 ether").Cmp(wethBalanceAfter) != 0 { + t.Fatalf("Invalid WETH balance: want 1") + } +} + +func FuzzWETHDeposit(f *testing.F) { + f.Add([]byte{1}) + f.Fuzz(func(t *testing.T, amountBytes []byte) { + if len(amountBytes) > 32 { + t.Skip() + } + amount := new(big.Int).SetBytes(amountBytes) + + // setup VM + vm, _ := w3vm.New( + w3vm.WithState(w3types.State{ + addrWETH: {Code: codeWETH}, + addrA: {Balance: w3.BigMaxUint256}, + }), + ) + + // Pre-check WETH balance + var wethBalanceBefore *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceBefore); err != nil { + t.Fatal(err) + } + + // Attempt deposit + vm.Apply(&w3types.Message{ + From: addrA, + To: &addrWETH, + Value: amount, + }) + + // Post-check WETH balance + var wethBalanceAfter *big.Int + if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceAfter); err != nil { + t.Fatal(err) + } + + // Verify balance increment + wantBalance := new(big.Int).Add(wethBalanceBefore, amount) + if wethBalanceAfter.Cmp(wantBalance) != 0 { + t.Fatalf("Invalid WETH balance: want %s, got %s", wantBalance, wethBalanceAfter) + } + }) +} diff --git a/w3vm/vm.go b/w3vm/vm.go index fe7b33fc..c23ea22d 100644 --- a/w3vm/vm.go +++ b/w3vm/vm.go @@ -459,7 +459,7 @@ type Option func(*VM) // WithChainConfig sets the chain config for the VM. // -// If not explicitly set, the chain config is set to [params.MainnetChainConfig]. +// If not provided, the chain config defaults to [params.MainnetChainConfig]. func WithChainConfig(cfg *params.ChainConfig) Option { return func(vm *VM) { vm.opts.chainConfig = cfg } } From ccb769de48345923357ccb85e385263fc1d027ce Mon Sep 17 00:00:00 2001 From: lmittmann Date: Thu, 10 Oct 2024 19:35:38 +0200 Subject: [PATCH 6/9] fix href --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2cf85562..19138984 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ func (f *getTransactionBySenderAndNonceFactory) HandleResponse(elem rpc.BatchEle ## Sponsors - - - ef logo + + + ef logo From 4e1e93eb72df2eb1b81b7a59ea3357e173955c12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:03:41 +0100 Subject: [PATCH 7/9] build(deps): bump github.com/charmbracelet/lipgloss from 0.13.0 to 1.0.0 (#198) Bumps [github.com/charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss) from 0.13.0 to 1.0.0. - [Release notes](https://github.com/charmbracelet/lipgloss/releases) - [Changelog](https://github.com/charmbracelet/lipgloss/blob/master/.goreleaser.yml) - [Commits](https://github.com/charmbracelet/lipgloss/compare/v0.13.0...v1.0.0) --- updated-dependencies: - dependency-name: github.com/charmbracelet/lipgloss dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4a30df66..4b97b800 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/lmittmann/w3 go 1.22 require ( - github.com/charmbracelet/lipgloss v0.13.0 + github.com/charmbracelet/lipgloss v1.0.0 github.com/ethereum/go-ethereum v1.14.8 github.com/google/go-cmp v0.6.0 github.com/holiman/uint256 v1.3.1 @@ -20,7 +20,7 @@ require ( github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect + github.com/charmbracelet/x/ansi v0.4.2 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect diff --git a/go.sum b/go.sum index a4c85b69..0371a773 100644 --- a/go.sum +++ b/go.sum @@ -66,10 +66,10 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= -github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= +github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= +github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= From cef96193556948bd34c80230abc66b0be77ae306 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:04:16 +0100 Subject: [PATCH 8/9] build(deps): bump github.com/holiman/uint256 from 1.3.1 to 1.3.2 (#201) Bumps [github.com/holiman/uint256](https://github.com/holiman/uint256) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/holiman/uint256/releases) - [Commits](https://github.com/holiman/uint256/compare/v1.3.1...v1.3.2) --- updated-dependencies: - dependency-name: github.com/holiman/uint256 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4b97b800..84e095ba 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/charmbracelet/lipgloss v1.0.0 github.com/ethereum/go-ethereum v1.14.8 github.com/google/go-cmp v0.6.0 - github.com/holiman/uint256 v1.3.1 + github.com/holiman/uint256 v1.3.2 golang.org/x/time v0.7.0 ) diff --git a/go.sum b/go.sum index 0371a773..cf146341 100644 --- a/go.sum +++ b/go.sum @@ -222,8 +222,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= -github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= From 3282e5a58b5df8822d5e5029c8cb4ff3cd3f91b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:09:19 +0100 Subject: [PATCH 9/9] build(deps): bump golang.org/x/time from 0.7.0 to 0.8.0 (#199) Bumps [golang.org/x/time](https://github.com/golang/time) from 0.7.0 to 0.8.0. - [Commits](https://github.com/golang/time/compare/v0.7.0...v0.8.0) --- updated-dependencies: - dependency-name: golang.org/x/time dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: lmittmann --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 84e095ba..62694f32 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/ethereum/go-ethereum v1.14.8 github.com/google/go-cmp v0.6.0 github.com/holiman/uint256 v1.3.2 - golang.org/x/time v0.7.0 + golang.org/x/time v0.8.0 ) require ( diff --git a/go.sum b/go.sum index cf146341..8911d81b 100644 --- a/go.sum +++ b/go.sum @@ -531,8 +531,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=