From 8d97ba880410df0df4f833c84c938f6ea144c2b9 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Sun, 28 Jan 2024 17:14:06 +0000 Subject: [PATCH] Artifacts --- docs/.nojekyll | 0 docs/CNAME | 1 + docs/css/index.css | 1087 + docs/favicon.webp | Bin 0 -> 7042 bytes docs/index.html | 31 + docs/js/components/App.d.ts | 2 + docs/js/components/App.d.ts.map | 1 + docs/js/components/App.js | 16 + docs/js/components/App.js.map | 1 + docs/js/components/Blockie.d.ts | 10 + docs/js/components/Blockie.d.ts.map | 1 + docs/js/components/Blockie.js | 149 + docs/js/components/Blockie.js.map | 1 + docs/js/components/Button.d.ts | 8 + docs/js/components/Button.d.ts.map | 1 + docs/js/components/Button.js | 10 + docs/js/components/Button.js.map | 1 + docs/js/components/ConfigureFunding.d.ts | 13 + docs/js/components/ConfigureFunding.d.ts.map | 1 + docs/js/components/ConfigureFunding.js | 121 + docs/js/components/ConfigureFunding.js.map | 1 + docs/js/components/ConfigureKeys.d.ts | 11 + docs/js/components/ConfigureKeys.d.ts.map | 1 + docs/js/components/ConfigureKeys.js | 54 + docs/js/components/ConfigureKeys.js.map | 1 + docs/js/components/Footer.d.ts | 2 + docs/js/components/Footer.d.ts.map | 1 + docs/js/components/Footer.js | 3 + docs/js/components/Footer.js.map | 1 + docs/js/components/Import.d.ts | 20 + docs/js/components/Import.d.ts.map | 1 + docs/js/components/Import.js | 99 + docs/js/components/Import.js.map | 1 + docs/js/components/ImportModal.d.ts | 9 + docs/js/components/ImportModal.d.ts.map | 1 + docs/js/components/ImportModal.js | 57 + docs/js/components/ImportModal.js.map | 1 + docs/js/components/Navbar.d.ts | 8 + docs/js/components/Navbar.d.ts.map | 1 + docs/js/components/Navbar.js | 29 + docs/js/components/Navbar.js.map | 1 + docs/js/components/Settings.d.ts | 9 + docs/js/components/Settings.d.ts.map | 1 + docs/js/components/Settings.js | 91 + docs/js/components/Settings.js.map | 1 + docs/js/components/Submit.d.ts | 50 + docs/js/components/Submit.d.ts.map | 1 + docs/js/components/Submit.js | 145 + docs/js/components/Submit.js.map | 1 + docs/js/components/Transactions.d.ts | 13 + docs/js/components/Transactions.d.ts.map | 1 + docs/js/components/Transactions.js | 125 + docs/js/components/Transactions.js.map | 1 + docs/js/components/Warns.d.ts | 7 + docs/js/components/Warns.d.ts.map | 1 + docs/js/components/Warns.js | 15 + docs/js/components/Warns.js.map | 1 + docs/js/constants.d.ts | 9 + docs/js/constants.d.ts.map | 1 + docs/js/constants.js | 5 + docs/js/constants.js.map | 1 + docs/js/index.d.ts | 2 + docs/js/index.d.ts.map | 1 + docs/js/index.js | 5 + docs/js/index.js.map | 1 + docs/js/library/DataURLCache.d.ts | 7 + docs/js/library/DataURLCache.d.ts.map | 1 + docs/js/library/DataURLCache.js | 15 + docs/js/library/DataURLCache.js.map | 1 + docs/js/library/asyncState.d.ts | 23 + docs/js/library/asyncState.d.ts.map | 1 + docs/js/library/asyncState.js | 42 + docs/js/library/asyncState.js.map | 1 + docs/js/library/bundleUtils.d.ts | 10 + docs/js/library/bundleUtils.d.ts.map | 1 + docs/js/library/bundleUtils.js | 96 + docs/js/library/bundleUtils.js.map | 1 + docs/js/library/flashbots.d.ts | 83 + docs/js/library/flashbots.d.ts.map | 1 + docs/js/library/flashbots.js | 66 + docs/js/library/flashbots.js.map | 1 + docs/js/library/provider.d.ts | 19 + docs/js/library/provider.d.ts.map | 1 + docs/js/library/provider.js | 118 + docs/js/library/provider.js.map | 1 + docs/js/library/utils.d.ts | 2 + docs/js/library/utils.d.ts.map | 1 + docs/js/library/utils.js | 7 + docs/js/library/utils.js.map | 1 + docs/js/stores.d.ts | 11 + docs/js/stores.d.ts.map | 1 + docs/js/stores.js | 80 + docs/js/stores.js.map | 1 + docs/js/types/apiTypes.d.ts | 16 + docs/js/types/apiTypes.d.ts.map | 1 + docs/js/types/apiTypes.js | 15 + docs/js/types/apiTypes.js.map | 1 + docs/js/types/bouquetTypes.d.ts | 23 + docs/js/types/bouquetTypes.d.ts.map | 1 + docs/js/types/bouquetTypes.js | 22 + docs/js/types/bouquetTypes.js.map | 1 + docs/js/types/ethereumTypes.d.ts | 15 + docs/js/types/ethereumTypes.d.ts.map | 1 + docs/js/types/ethereumTypes.js | 95 + docs/js/types/ethereumTypes.js.map | 1 + docs/js/types/interceptorTypes.d.ts | 74 + docs/js/types/interceptorTypes.d.ts.map | 1 + docs/js/types/interceptorTypes.js | 96 + docs/js/types/interceptorTypes.js.map | 1 + docs/js/types/types.d.ts | 69 + docs/js/types/types.d.ts.map | 1 + docs/js/types/types.js | 4 + docs/js/types/types.js.map | 1 + docs/ts/components/App.tsx | 41 + docs/ts/components/Blockie.tsx | 197 + docs/ts/components/Button.tsx | 25 + docs/ts/components/ConfigureFunding.tsx | 219 + docs/ts/components/ConfigureKeys.tsx | 88 + docs/ts/components/Footer.tsx | 19 + docs/ts/components/Import.tsx | 170 + docs/ts/components/ImportModal.tsx | 82 + docs/ts/components/Navbar.tsx | 69 + docs/ts/components/Settings.tsx | 136 + docs/ts/components/Submit.tsx | 286 + docs/ts/components/Transactions.tsx | 212 + docs/ts/components/Warns.tsx | 22 + docs/ts/constants.ts | 4 + docs/ts/index.tsx | 4 + docs/ts/library/DataURLCache.ts | 12 + docs/ts/library/asyncState.ts | 49 + docs/ts/library/bundleUtils.ts | 103 + docs/ts/library/flashbots.ts | 141 + docs/ts/library/provider.ts | 151 + docs/ts/library/utils.ts | 7 + docs/ts/stores.ts | 80 + docs/ts/types/apiTypes.ts | 24 + docs/ts/types/bouquetTypes.ts | 25 + docs/ts/types/ethereumTypes.ts | 107 + docs/ts/types/interceptorTypes.ts | 137 + docs/ts/types/types.ts | 59 + .../@preact/signals-core/signals-core.d.ts | 17 + .../@preact/signals-core/signals-core.js | 1 + .../@preact/signals-core/signals-core.js.map | 1 + .../@preact/signals-core/signals-core.min.js | 1 + .../signals-core/signals-core.min.js.map | 1 + .../@preact/signals-core/signals-core.mjs | 1 + .../@preact/signals-core/signals-core.mjs.map | 1 + .../signals-core/signals-core.module.js | 1 + .../signals-core/signals-core.module.js.map | 1 + docs/vendor/@preact/signals/signals.d.ts | 40 + docs/vendor/@preact/signals/signals.js | 1 + docs/vendor/@preact/signals/signals.js.map | 1 + docs/vendor/@preact/signals/signals.min.js | 1 + .../vendor/@preact/signals/signals.min.js.map | 1 + docs/vendor/@preact/signals/signals.mjs | 1 + docs/vendor/@preact/signals/signals.mjs.map | 1 + docs/vendor/@preact/signals/signals.module.js | 1 + .../@preact/signals/signals.module.js.map | 1 + docs/vendor/ethers/README.md | 22 + docs/vendor/ethers/ethers.js | 23750 +++++++++++++++ docs/vendor/ethers/ethers.js.map | 1 + docs/vendor/ethers/ethers.min.js | 1 + docs/vendor/ethers/ethers.umd.js | 23946 ++++++++++++++++ docs/vendor/ethers/ethers.umd.js.map | 1 + docs/vendor/ethers/ethers.umd.min.js | 1 + docs/vendor/ethers/wordlists-extra.js | 1595 + docs/vendor/ethers/wordlists-extra.js.map | 1 + docs/vendor/ethers/wordlists-extra.min.js | 1 + docs/vendor/funtypes/assertType.d.ts | 2 + docs/vendor/funtypes/asynccontract.d.ts | 10 + docs/vendor/funtypes/chunk-25d2eebd.js | 1033 + docs/vendor/funtypes/chunk-c1bc36ba.mjs | 1073 + docs/vendor/funtypes/contract.d.ts | 10 + docs/vendor/funtypes/errors.d.ts | 8 + docs/vendor/funtypes/index.d.ts | 32 + docs/vendor/funtypes/index.js | 49 + docs/vendor/funtypes/index.mjs | 48 + docs/vendor/funtypes/readonly.d.ts | 32 + docs/vendor/funtypes/readonly.js | 56 + docs/vendor/funtypes/readonly.mjs | 50 + docs/vendor/funtypes/result.d.ts | 47 + docs/vendor/funtypes/runtype.d.ts | 194 + docs/vendor/funtypes/show.d.ts | 4 + docs/vendor/funtypes/showValue.d.ts | 2 + docs/vendor/funtypes/types/Enum.d.ts | 10 + docs/vendor/funtypes/types/KeyOf.d.ts | 6 + docs/vendor/funtypes/types/Mutable.d.ts | 10 + docs/vendor/funtypes/types/Named.d.ts | 8 + docs/vendor/funtypes/types/Object.d.ts | 35 + docs/vendor/funtypes/types/ParsedValue.d.ts | 14 + docs/vendor/funtypes/types/Readonly.d.ts | 10 + docs/vendor/funtypes/types/Record.d.ts | 28 + docs/vendor/funtypes/types/Sealed.d.ts | 10 + docs/vendor/funtypes/types/array.d.ts | 15 + docs/vendor/funtypes/types/brand.d.ts | 10 + docs/vendor/funtypes/types/constraint.d.ts | 20 + docs/vendor/funtypes/types/instanceof.d.ts | 9 + docs/vendor/funtypes/types/intersect.d.ts | 13 + docs/vendor/funtypes/types/lazy.d.ts | 10 + docs/vendor/funtypes/types/literal.d.ts | 22 + docs/vendor/funtypes/types/never.d.ts | 8 + docs/vendor/funtypes/types/primative.d.ts | 37 + docs/vendor/funtypes/types/tuple.d.ts | 23 + docs/vendor/funtypes/types/union.d.ts | 23 + docs/vendor/funtypes/types/unknown.d.ts | 8 + docs/vendor/funtypes/util.d.ts | 3 + docs/vendor/preact/hooks/hooks.js | 2 + docs/vendor/preact/hooks/hooks.js.map | 1 + docs/vendor/preact/hooks/hooks.mjs | 2 + docs/vendor/preact/hooks/hooks.module.js | 2 + docs/vendor/preact/hooks/hooks.module.js.map | 1 + docs/vendor/preact/hooks/hooks.umd.js | 2 + docs/vendor/preact/hooks/hooks.umd.js.map | 1 + docs/vendor/preact/jsx-runtime/jsxRuntime.js | 2 + .../preact/jsx-runtime/jsxRuntime.js.map | 1 + docs/vendor/preact/jsx-runtime/jsxRuntime.mjs | 2 + .../preact/jsx-runtime/jsxRuntime.module.js | 2 + .../jsx-runtime/jsxRuntime.module.js.map | 1 + .../preact/jsx-runtime/jsxRuntime.umd.js | 2 + .../preact/jsx-runtime/jsxRuntime.umd.js.map | 1 + docs/vendor/preact/preact.js | 2 + docs/vendor/preact/preact.js.map | 1 + docs/vendor/preact/preact.min.js | 2 + docs/vendor/preact/preact.min.js.map | 1 + docs/vendor/preact/preact.mjs | 2 + docs/vendor/preact/preact.module.js | 2 + docs/vendor/preact/preact.module.js.map | 1 + docs/vendor/preact/preact.umd.js | 2 + docs/vendor/preact/preact.umd.js.map | 1 + 229 files changed, 58157 insertions(+) create mode 100644 docs/.nojekyll create mode 100644 docs/CNAME create mode 100644 docs/css/index.css create mode 100644 docs/favicon.webp create mode 100644 docs/index.html create mode 100644 docs/js/components/App.d.ts create mode 100644 docs/js/components/App.d.ts.map create mode 100644 docs/js/components/App.js create mode 100644 docs/js/components/App.js.map create mode 100644 docs/js/components/Blockie.d.ts create mode 100644 docs/js/components/Blockie.d.ts.map create mode 100644 docs/js/components/Blockie.js create mode 100644 docs/js/components/Blockie.js.map create mode 100644 docs/js/components/Button.d.ts create mode 100644 docs/js/components/Button.d.ts.map create mode 100644 docs/js/components/Button.js create mode 100644 docs/js/components/Button.js.map create mode 100644 docs/js/components/ConfigureFunding.d.ts create mode 100644 docs/js/components/ConfigureFunding.d.ts.map create mode 100644 docs/js/components/ConfigureFunding.js create mode 100644 docs/js/components/ConfigureFunding.js.map create mode 100644 docs/js/components/ConfigureKeys.d.ts create mode 100644 docs/js/components/ConfigureKeys.d.ts.map create mode 100644 docs/js/components/ConfigureKeys.js create mode 100644 docs/js/components/ConfigureKeys.js.map create mode 100644 docs/js/components/Footer.d.ts create mode 100644 docs/js/components/Footer.d.ts.map create mode 100644 docs/js/components/Footer.js create mode 100644 docs/js/components/Footer.js.map create mode 100644 docs/js/components/Import.d.ts create mode 100644 docs/js/components/Import.d.ts.map create mode 100644 docs/js/components/Import.js create mode 100644 docs/js/components/Import.js.map create mode 100644 docs/js/components/ImportModal.d.ts create mode 100644 docs/js/components/ImportModal.d.ts.map create mode 100644 docs/js/components/ImportModal.js create mode 100644 docs/js/components/ImportModal.js.map create mode 100644 docs/js/components/Navbar.d.ts create mode 100644 docs/js/components/Navbar.d.ts.map create mode 100644 docs/js/components/Navbar.js create mode 100644 docs/js/components/Navbar.js.map create mode 100644 docs/js/components/Settings.d.ts create mode 100644 docs/js/components/Settings.d.ts.map create mode 100644 docs/js/components/Settings.js create mode 100644 docs/js/components/Settings.js.map create mode 100644 docs/js/components/Submit.d.ts create mode 100644 docs/js/components/Submit.d.ts.map create mode 100644 docs/js/components/Submit.js create mode 100644 docs/js/components/Submit.js.map create mode 100644 docs/js/components/Transactions.d.ts create mode 100644 docs/js/components/Transactions.d.ts.map create mode 100644 docs/js/components/Transactions.js create mode 100644 docs/js/components/Transactions.js.map create mode 100644 docs/js/components/Warns.d.ts create mode 100644 docs/js/components/Warns.d.ts.map create mode 100644 docs/js/components/Warns.js create mode 100644 docs/js/components/Warns.js.map create mode 100644 docs/js/constants.d.ts create mode 100644 docs/js/constants.d.ts.map create mode 100644 docs/js/constants.js create mode 100644 docs/js/constants.js.map create mode 100644 docs/js/index.d.ts create mode 100644 docs/js/index.d.ts.map create mode 100644 docs/js/index.js create mode 100644 docs/js/index.js.map create mode 100644 docs/js/library/DataURLCache.d.ts create mode 100644 docs/js/library/DataURLCache.d.ts.map create mode 100644 docs/js/library/DataURLCache.js create mode 100644 docs/js/library/DataURLCache.js.map create mode 100644 docs/js/library/asyncState.d.ts create mode 100644 docs/js/library/asyncState.d.ts.map create mode 100644 docs/js/library/asyncState.js create mode 100644 docs/js/library/asyncState.js.map create mode 100644 docs/js/library/bundleUtils.d.ts create mode 100644 docs/js/library/bundleUtils.d.ts.map create mode 100644 docs/js/library/bundleUtils.js create mode 100644 docs/js/library/bundleUtils.js.map create mode 100644 docs/js/library/flashbots.d.ts create mode 100644 docs/js/library/flashbots.d.ts.map create mode 100644 docs/js/library/flashbots.js create mode 100644 docs/js/library/flashbots.js.map create mode 100644 docs/js/library/provider.d.ts create mode 100644 docs/js/library/provider.d.ts.map create mode 100644 docs/js/library/provider.js create mode 100644 docs/js/library/provider.js.map create mode 100644 docs/js/library/utils.d.ts create mode 100644 docs/js/library/utils.d.ts.map create mode 100644 docs/js/library/utils.js create mode 100644 docs/js/library/utils.js.map create mode 100644 docs/js/stores.d.ts create mode 100644 docs/js/stores.d.ts.map create mode 100644 docs/js/stores.js create mode 100644 docs/js/stores.js.map create mode 100644 docs/js/types/apiTypes.d.ts create mode 100644 docs/js/types/apiTypes.d.ts.map create mode 100644 docs/js/types/apiTypes.js create mode 100644 docs/js/types/apiTypes.js.map create mode 100644 docs/js/types/bouquetTypes.d.ts create mode 100644 docs/js/types/bouquetTypes.d.ts.map create mode 100644 docs/js/types/bouquetTypes.js create mode 100644 docs/js/types/bouquetTypes.js.map create mode 100644 docs/js/types/ethereumTypes.d.ts create mode 100644 docs/js/types/ethereumTypes.d.ts.map create mode 100644 docs/js/types/ethereumTypes.js create mode 100644 docs/js/types/ethereumTypes.js.map create mode 100644 docs/js/types/interceptorTypes.d.ts create mode 100644 docs/js/types/interceptorTypes.d.ts.map create mode 100644 docs/js/types/interceptorTypes.js create mode 100644 docs/js/types/interceptorTypes.js.map create mode 100644 docs/js/types/types.d.ts create mode 100644 docs/js/types/types.d.ts.map create mode 100644 docs/js/types/types.js create mode 100644 docs/js/types/types.js.map create mode 100644 docs/ts/components/App.tsx create mode 100644 docs/ts/components/Blockie.tsx create mode 100644 docs/ts/components/Button.tsx create mode 100644 docs/ts/components/ConfigureFunding.tsx create mode 100644 docs/ts/components/ConfigureKeys.tsx create mode 100644 docs/ts/components/Footer.tsx create mode 100644 docs/ts/components/Import.tsx create mode 100644 docs/ts/components/ImportModal.tsx create mode 100644 docs/ts/components/Navbar.tsx create mode 100644 docs/ts/components/Settings.tsx create mode 100644 docs/ts/components/Submit.tsx create mode 100644 docs/ts/components/Transactions.tsx create mode 100644 docs/ts/components/Warns.tsx create mode 100644 docs/ts/constants.ts create mode 100644 docs/ts/index.tsx create mode 100644 docs/ts/library/DataURLCache.ts create mode 100644 docs/ts/library/asyncState.ts create mode 100644 docs/ts/library/bundleUtils.ts create mode 100644 docs/ts/library/flashbots.ts create mode 100644 docs/ts/library/provider.ts create mode 100644 docs/ts/library/utils.ts create mode 100644 docs/ts/stores.ts create mode 100644 docs/ts/types/apiTypes.ts create mode 100644 docs/ts/types/bouquetTypes.ts create mode 100644 docs/ts/types/ethereumTypes.ts create mode 100644 docs/ts/types/interceptorTypes.ts create mode 100644 docs/ts/types/types.ts create mode 100644 docs/vendor/@preact/signals-core/signals-core.d.ts create mode 100644 docs/vendor/@preact/signals-core/signals-core.js create mode 100644 docs/vendor/@preact/signals-core/signals-core.js.map create mode 100644 docs/vendor/@preact/signals-core/signals-core.min.js create mode 100644 docs/vendor/@preact/signals-core/signals-core.min.js.map create mode 100644 docs/vendor/@preact/signals-core/signals-core.mjs create mode 100644 docs/vendor/@preact/signals-core/signals-core.mjs.map create mode 100644 docs/vendor/@preact/signals-core/signals-core.module.js create mode 100644 docs/vendor/@preact/signals-core/signals-core.module.js.map create mode 100644 docs/vendor/@preact/signals/signals.d.ts create mode 100644 docs/vendor/@preact/signals/signals.js create mode 100644 docs/vendor/@preact/signals/signals.js.map create mode 100644 docs/vendor/@preact/signals/signals.min.js create mode 100644 docs/vendor/@preact/signals/signals.min.js.map create mode 100644 docs/vendor/@preact/signals/signals.mjs create mode 100644 docs/vendor/@preact/signals/signals.mjs.map create mode 100644 docs/vendor/@preact/signals/signals.module.js create mode 100644 docs/vendor/@preact/signals/signals.module.js.map create mode 100644 docs/vendor/ethers/README.md create mode 100644 docs/vendor/ethers/ethers.js create mode 100644 docs/vendor/ethers/ethers.js.map create mode 100644 docs/vendor/ethers/ethers.min.js create mode 100644 docs/vendor/ethers/ethers.umd.js create mode 100644 docs/vendor/ethers/ethers.umd.js.map create mode 100644 docs/vendor/ethers/ethers.umd.min.js create mode 100644 docs/vendor/ethers/wordlists-extra.js create mode 100644 docs/vendor/ethers/wordlists-extra.js.map create mode 100644 docs/vendor/ethers/wordlists-extra.min.js create mode 100644 docs/vendor/funtypes/assertType.d.ts create mode 100644 docs/vendor/funtypes/asynccontract.d.ts create mode 100644 docs/vendor/funtypes/chunk-25d2eebd.js create mode 100644 docs/vendor/funtypes/chunk-c1bc36ba.mjs create mode 100644 docs/vendor/funtypes/contract.d.ts create mode 100644 docs/vendor/funtypes/errors.d.ts create mode 100644 docs/vendor/funtypes/index.d.ts create mode 100644 docs/vendor/funtypes/index.js create mode 100644 docs/vendor/funtypes/index.mjs create mode 100644 docs/vendor/funtypes/readonly.d.ts create mode 100644 docs/vendor/funtypes/readonly.js create mode 100644 docs/vendor/funtypes/readonly.mjs create mode 100644 docs/vendor/funtypes/result.d.ts create mode 100644 docs/vendor/funtypes/runtype.d.ts create mode 100644 docs/vendor/funtypes/show.d.ts create mode 100644 docs/vendor/funtypes/showValue.d.ts create mode 100644 docs/vendor/funtypes/types/Enum.d.ts create mode 100644 docs/vendor/funtypes/types/KeyOf.d.ts create mode 100644 docs/vendor/funtypes/types/Mutable.d.ts create mode 100644 docs/vendor/funtypes/types/Named.d.ts create mode 100644 docs/vendor/funtypes/types/Object.d.ts create mode 100644 docs/vendor/funtypes/types/ParsedValue.d.ts create mode 100644 docs/vendor/funtypes/types/Readonly.d.ts create mode 100644 docs/vendor/funtypes/types/Record.d.ts create mode 100644 docs/vendor/funtypes/types/Sealed.d.ts create mode 100644 docs/vendor/funtypes/types/array.d.ts create mode 100644 docs/vendor/funtypes/types/brand.d.ts create mode 100644 docs/vendor/funtypes/types/constraint.d.ts create mode 100644 docs/vendor/funtypes/types/instanceof.d.ts create mode 100644 docs/vendor/funtypes/types/intersect.d.ts create mode 100644 docs/vendor/funtypes/types/lazy.d.ts create mode 100644 docs/vendor/funtypes/types/literal.d.ts create mode 100644 docs/vendor/funtypes/types/never.d.ts create mode 100644 docs/vendor/funtypes/types/primative.d.ts create mode 100644 docs/vendor/funtypes/types/tuple.d.ts create mode 100644 docs/vendor/funtypes/types/union.d.ts create mode 100644 docs/vendor/funtypes/types/unknown.d.ts create mode 100644 docs/vendor/funtypes/util.d.ts create mode 100644 docs/vendor/preact/hooks/hooks.js create mode 100644 docs/vendor/preact/hooks/hooks.js.map create mode 100644 docs/vendor/preact/hooks/hooks.mjs create mode 100644 docs/vendor/preact/hooks/hooks.module.js create mode 100644 docs/vendor/preact/hooks/hooks.module.js.map create mode 100644 docs/vendor/preact/hooks/hooks.umd.js create mode 100644 docs/vendor/preact/hooks/hooks.umd.js.map create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.js create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.js.map create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.mjs create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.module.js create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.module.js.map create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.umd.js create mode 100644 docs/vendor/preact/jsx-runtime/jsxRuntime.umd.js.map create mode 100644 docs/vendor/preact/preact.js create mode 100644 docs/vendor/preact/preact.js.map create mode 100644 docs/vendor/preact/preact.min.js create mode 100644 docs/vendor/preact/preact.min.js.map create mode 100644 docs/vendor/preact/preact.mjs create mode 100644 docs/vendor/preact/preact.module.js create mode 100644 docs/vendor/preact/preact.module.js.map create mode 100644 docs/vendor/preact/preact.umd.js create mode 100644 docs/vendor/preact/preact.umd.js.map diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..e83ee5b --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +bouquet.dark.florist diff --git a/docs/css/index.css b/docs/css/index.css new file mode 100644 index 0000000..163d01c --- /dev/null +++ b/docs/css/index.css @@ -0,0 +1,1087 @@ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type='number'] { + -moz-appearance: textfield; + /* Firefox */ +} + +/* ! tailwindcss v3.2.7 | MIT License | https://tailwindcss.com */ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +*/ + +html { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + /* 4 */ + font-feature-settings: normal; + /* 5 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, +textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role='button'] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, +::before, +::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.fixed { + position: fixed; +} + +.inset-0 { + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mt-auto { + margin-top: auto; +} + +.block { + display: block; +} + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.hidden { + display: none; +} + +.h-12 { + height: 3rem; +} + +.h-16 { + height: 4rem; +} + +.h-4 { + height: 1rem; +} + +.h-6 { + height: 1.5rem; +} + +.h-8 { + height: 2rem; +} + +.h-96 { + height: 24rem; +} + +.h-full { + height: 100%; +} + +.h-max { + height: -moz-max-content; + height: max-content; +} + +.min-h-\[96px\] { + min-height: 96px; +} + +.min-h-screen { + min-height: 100vh; +} + +.w-10 { + width: 2.5rem; +} + +.w-16 { + width: 4rem; +} + +.w-24 { + width: 6rem; +} + +.w-4 { + width: 1rem; +} + +.w-8 { + width: 2rem; +} + +.w-96 { + width: 24rem; +} + +.w-full { + width: 100%; +} + +.w-max { + width: -moz-max-content; + width: max-content; +} + +.w-min { + width: -moz-min-content; + width: min-content; +} + +.w-screen { + width: 100vw; +} + +.max-w-full { + max-width: 100%; +} + +.max-w-screen-xl { + max-width: 1280px; +} + +.max-w-xl { + max-width: 36rem; +} + +.flex-grow { + flex-grow: 1; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.animate-spin { + animation: spin 1s linear infinite; +} + +.flex-row { + flex-direction: row; +} + +.flex-col { + flex-direction: column; +} + +.flex-col-reverse { + flex-direction: column-reverse; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.items-end { + align-items: flex-end; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +.gap-1 { + gap: 0.25rem; +} + +.gap-2 { + gap: 0.5rem; +} + +.gap-4 { + gap: 1rem; +} + +.gap-6 { + gap: 1.5rem; +} + +.gap-8 { + gap: 2rem; +} + +.overflow-hidden { + overflow: hidden; +} + +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.break-all { + word-break: break-all; +} + +.border { + border-width: 1px; +} + +.border-green-400 { + --tw-border-opacity: 1; + border-color: rgb(74 222 128 / var(--tw-border-opacity)); +} + +.border-green-400\/50 { + border-color: rgb(74 222 128 / 0.5); +} + +.border-orange-400\/50 { + border-color: rgb(251 146 60 / 0.5); +} + +.border-red-400 { + --tw-border-opacity: 1; + border-color: rgb(248 113 113 / var(--tw-border-opacity)); +} + +.border-red-400\/50 { + border-color: rgb(248 113 113 / 0.5); +} + +.border-slate-400\/30 { + border-color: rgb(148 163 184 / 0.3); +} + +.border-white\/50 { + border-color: rgb(255 255 255 / 0.5); +} + +.border-white\/90 { + border-color: rgb(255 255 255 / 0.9); +} + +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + +.bg-gray-500\/30 { + background-color: rgb(107 114 128 / 0.3); +} + +.bg-gray-500\/50 { + background-color: rgb(107 114 128 / 0.5); +} + +.bg-green-200\/10 { + background-color: rgb(187 247 208 / 0.1); +} + +.bg-green-400\/10 { + background-color: rgb(74 222 128 / 0.1); +} + +.bg-orange-400\/10 { + background-color: rgb(251 146 60 / 0.1); +} + +.bg-red-200\/10 { + background-color: rgb(254 202 202 / 0.1); +} + +.bg-red-400\/10 { + background-color: rgb(248 113 113 / 0.1); +} + +.bg-transparent { + background-color: transparent; +} + +.bg-white\/10 { + background-color: rgb(255 255 255 / 0.1); +} + +.p-2 { + padding: 0.5rem; +} + +.p-4 { + padding: 1rem; +} + +.p-6 { + padding: 1.5rem; +} + +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.px-8 { + padding-left: 2rem; + padding-right: 2rem; +} + +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} + +.pl-4 { + padding-left: 1rem; +} + +.text-right { + text-align: right; +} + +.font-mono { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; +} + +.font-serif { + font-family: Inter, sans-serif; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + +.font-bold { + font-weight: 700; +} + +.font-extrabold { + font-weight: 800; +} + +.font-medium { + font-weight: 500; +} + +.font-semibold { + font-weight: 600; +} + +.leading-tight { + line-height: 1.25; +} + +.text-accent { + --tw-text-opacity: 1; + color: rgb(108 207 246 / var(--tw-text-opacity)); +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-orange-600 { + --tw-text-opacity: 1; + color: rgb(234 88 12 / var(--tw-text-opacity)); +} + +.text-primary { + --tw-text-opacity: 1; + color: rgb(255 255 252 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-white\/50 { + color: rgb(255 255 255 / 0.5); +} + +.text-white\/75 { + color: rgb(255 255 255 / 0.75); +} + +.underline { + text-decoration-line: underline; +} + +.opacity-25 { + opacity: 0.25; +} + +.opacity-75 { + opacity: 0.75; +} + +.outline-none { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.filter { + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +.duration-200 { + transition-duration: 200ms; +} + +.placeholder\:text-gray-600::-moz-placeholder { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.placeholder\:text-gray-600::placeholder { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.focus-within\:border-white\/80:focus-within { + border-color: rgb(255 255 255 / 0.8); +} + +.focus-within\:border-white\/90:focus-within { + border-color: rgb(255 255 255 / 0.9); +} + +.focus-within\:bg-white\/5:focus-within { + background-color: rgb(255 255 255 / 0.05); +} + +.hover\:rotate-45:hover { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:underline:hover { + text-decoration-line: underline; +} + +.focus\:border-white\/90:focus { + border-color: rgb(255 255 255 / 0.9); +} + +.focus\:bg-gray-500:focus { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); +} + +.focus\:bg-gray-500\/20:focus { + background-color: rgb(107 114 128 / 0.2); +} + +.disabled\:opacity-50:disabled { + opacity: 0.5; +} + +@media (min-width: 640px) { + .sm\:block { + display: block; + } + + .sm\:flex-row { + flex-direction: row; + } + + .sm\:p-4 { + padding: 1rem; + } + + .sm\:px-0 { + padding-left: 0px; + padding-right: 0px; + } + + .sm\:py-6 { + padding-top: 1.5rem; + padding-bottom: 1.5rem; + } + + .sm\:text-base { + font-size: 1rem; + line-height: 1.5rem; + } + + .sm\:text-lg { + font-size: 1.125rem; + line-height: 1.75rem; + } +} + +@media (min-width: 768px) { + .md\:pt-24 { + padding-top: 6rem; + } +} diff --git a/docs/favicon.webp b/docs/favicon.webp new file mode 100644 index 0000000000000000000000000000000000000000..11dcc7c3ceea41fad0d08e32e4fd31699cbce391 GIT binary patch literal 7042 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 literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..4641066 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,31 @@ + + + + bouquet + + + + + + + + + +
+ + + + + diff --git a/docs/js/components/App.d.ts b/docs/js/components/App.d.ts new file mode 100644 index 0000000..1ce870f --- /dev/null +++ b/docs/js/components/App.d.ts @@ -0,0 +1,2 @@ +export declare function App(): import("preact").JSX.Element; +//# sourceMappingURL=App.d.ts.map \ No newline at end of file diff --git a/docs/js/components/App.d.ts.map b/docs/js/components/App.d.ts.map new file mode 100644 index 0000000..f77e1bb --- /dev/null +++ b/docs/js/components/App.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../ts/components/App.tsx"],"names":[],"mappings":"AAWA,wBAAgB,GAAG,iCA6BlB"} \ No newline at end of file diff --git a/docs/js/components/App.js b/docs/js/components/App.js new file mode 100644 index 0000000..dd63499 --- /dev/null +++ b/docs/js/components/App.js @@ -0,0 +1,16 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime"; +import { Import } from './Import.js'; +import { Submit } from './Submit.js'; +import { Button } from './Button.js'; +import { Transactions } from './Transactions.js'; +import { connectBrowserProvider } from '../library/provider.js'; +import { Navbar } from './Navbar.js'; +import { createGlobalState } from '../stores.js'; +import { Footer } from './Footer.js'; +import { ConfigureKeys } from './ConfigureKeys.js'; +import { ConfigureFunding } from './ConfigureFunding.js'; +export function App() { + const state = createGlobalState(); + return (_jsxs("main", { class: 'bg-black text-primary w-screen max-w-screen overflow-hidden min-h-screen sm:p-4 p-6 gap-4 font-serif flex flex-col items-center max-w-screen-xl', children: [_jsx(Navbar, { ...state }), _jsx("div", { className: 'p-4 mt-4 flex flex-col gap-8 w-full', children: !state.provider.value && state.bundle.value ? (_jsxs("article", { className: 'items-center flex flex-col gap-4 py-8', children: [_jsx("h2", { class: 'text-2xl font-bold', children: "Welcome Back" }), _jsx(Button, { onClick: () => connectBrowserProvider(state.provider, state.blockInfo, state.bundle.peek()?.containsFundingTx ? state.signers : undefined, state.appSettings), children: "Connect Wallet" })] })) : (_jsxs(_Fragment, { children: [_jsx(Import, { ...state }), state.bundle.value ? _jsx(Transactions, { ...state }) : null, _jsxs("h2", { className: 'font-bold text-2xl', children: [_jsx("span", { class: 'text-gray-500', children: "2." }), " Configure"] }), state.bundle.value ? (_jsxs(_Fragment, { children: [_jsx(ConfigureKeys, { ...state }), _jsx(ConfigureFunding, { ...state })] })) : _jsx("p", { children: "No transactions imported yet." }), _jsx(Submit, { ...state })] })) }), _jsx(Footer, {})] })); +} +//# sourceMappingURL=App.js.map \ No newline at end of file diff --git a/docs/js/components/App.js.map b/docs/js/components/App.js.map new file mode 100644 index 0000000..1d9716f --- /dev/null +++ b/docs/js/components/App.js.map @@ -0,0 +1 @@ +{"version":3,"file":"App.js","sourceRoot":"","sources":["../../ts/components/App.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,MAAM,UAAU,GAAG;IAClB,MAAM,KAAK,GAAG,iBAAiB,EAAE,CAAA;IAEjC,OAAO,CACN,gBAAM,KAAK,EAAC,iJAAiJ,aAC3J,KAAC,MAAM,OAAK,KAAK,GAAI,EACrB,cAAK,SAAS,EAAC,qCAAqC,YAClD,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAC9C,mBAAS,SAAS,EAAC,uCAAuC,aACzD,aAAI,KAAK,EAAC,oBAAoB,6BAAkB,EAChD,KAAC,MAAM,IACN,OAAO,EAAE,GAAG,EAAE,CAAC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,+BAGrJ,IACA,CACV,CAAC,CAAC,CAAC,CACH,8BACC,KAAC,MAAM,OAAK,KAAK,GAAI,EACpB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAC,YAAY,OAAK,KAAK,GAAI,CAAC,CAAC,CAAC,IAAI,EACxD,cAAI,SAAS,EAAC,oBAAoB,aAAC,eAAM,KAAK,EAAC,eAAe,mBAAU,kBAAe,EACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,8BAAE,KAAC,aAAa,OAAK,KAAK,GAAI,EAAA,KAAC,gBAAgB,OAAK,KAAK,GAAI,IAAG,CAAC,CAAC,CAAC,CAAC,wDAAoC,EAC/H,KAAC,MAAM,OAAK,KAAK,GAAI,IACnB,CACH,GACI,EACP,KAAC,MAAM,KAAG,IACJ,CACP,CAAA;AACF,CAAC","sourcesContent":["import { Import } from './Import.js'\nimport { Submit } from './Submit.js'\nimport { Button } from './Button.js'\nimport { Transactions } from './Transactions.js'\nimport { connectBrowserProvider } from '../library/provider.js'\nimport { Navbar } from './Navbar.js'\nimport { createGlobalState } from '../stores.js'\nimport { Footer } from './Footer.js'\nimport { ConfigureKeys } from './ConfigureKeys.js'\nimport { ConfigureFunding } from './ConfigureFunding.js'\n\nexport function App() {\n\tconst state = createGlobalState()\n\n\treturn (\n\t\t
\n\t\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{!state.provider.value && state.bundle.value ? (\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t

Welcome Back

\n\t\t\t\t\t\t\t connectBrowserProvider(state.provider, state.blockInfo, state.bundle.peek()?.containsFundingTx ? state.signers : undefined, state.appSettings)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tConnect Wallet\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{state.bundle.value ? : null}\n\t\t\t\t\t\t\t

2. Configure

\n\t\t\t\t\t\t\t{state.bundle.value ? (<>) :

No transactions imported yet.

}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t)}\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t)\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Blockie.d.ts b/docs/js/components/Blockie.d.ts new file mode 100644 index 0000000..899aa4f --- /dev/null +++ b/docs/js/components/Blockie.d.ts @@ -0,0 +1,10 @@ +import { JSX } from 'preact/jsx-runtime'; +import { ReadonlySignal, Signal } from '@preact/signals'; +interface BlockieProps { + address: Signal | ReadonlySignal; + scale?: Signal; + style?: JSX.CSSProperties; +} +export declare function Blockie(props: BlockieProps): JSX.Element; +export {}; +//# sourceMappingURL=Blockie.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Blockie.d.ts.map b/docs/js/components/Blockie.d.ts.map new file mode 100644 index 0000000..b0d528d --- /dev/null +++ b/docs/js/components/Blockie.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Blockie.d.ts","sourceRoot":"","sources":["../../ts/components/Blockie.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAmB,MAAM,iBAAiB,CAAA;AA6CzE,UAAU,YAAY;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,KAAK,CAAC,EAAE,GAAG,CAAC,aAAa,CAAA;CACzB;AA+HD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,eAmB1C"} \ No newline at end of file diff --git a/docs/js/components/Blockie.js b/docs/js/components/Blockie.js new file mode 100644 index 0000000..45a6bfa --- /dev/null +++ b/docs/js/components/Blockie.js @@ -0,0 +1,149 @@ +import { jsx as _jsx } from "preact/jsx-runtime"; +import { useSignalEffect } from '@preact/signals'; +import { useAsyncState } from '../library/asyncState.js'; +import { DataURLCache } from '../library/DataURLCache.js'; +const dataURLCache = new DataURLCache(); +class Future { + constructor() { + this.then = (onfulfilled, onrejected) => { + return this.promise.then(onfulfilled, onrejected); + }; + this.resolve = (value) => { + this.resolveFunction(value); + }; + this.reject = (reason) => { + this.rejectFunction(reason); + }; + let resolveFunction; + let rejectFunction; + this.promise = new Promise((resolve, reject) => { + resolveFunction = resolve; + rejectFunction = reject; + }); + // the function passed to the Promise constructor is called before the constructor returns, so we can be sure the resolve and reject functions have been set by here even if the compiler can't verify + this.resolveFunction = resolveFunction; + this.rejectFunction = rejectFunction; + } + get asPromise() { return this.promise; } +} +function addressString(address) { + return `0x${address.toString(16).padStart(40, '0')}`; +} +function generateIdenticon(address, scale, canvasRef) { + // NOTE -- Majority of this code is referenced from: https://github.com/alexvandesande/blockies + // Mostly to ensure congruence to Ethereum Mist's Identicons + // The random number is a js implementation of the Xorshift PRNG + const randseed = new Array(4); // Xorshift: [x, y, z, w] 32 bit values + function seedrand(seed) { + for (let i = 0; i < randseed.length; i++) { + randseed[i] = 0; + } + for (let i = 0; i < seed.length; i++) { + randseed[i % 4] = ((randseed[i % 4] << 5) - randseed[i % 4]) + seed.charCodeAt(i); + } + } + function rand() { + // based on Java's String.hashCode(), expanded to 4 32bit values + const t = randseed[0] ^ (randseed[0] << 11); + randseed[0] = randseed[1]; + randseed[1] = randseed[2]; + randseed[2] = randseed[3]; + randseed[3] = (randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8)); + return (randseed[3] >>> 0) / ((1 << 31) >>> 0); + } + function createColor() { + // saturation is the whole color spectrum + const h = Math.floor(rand() * 360); + // saturation goes from 40 to 100, it avoids greyish colors + const s = ((rand() * 60) + 40) + '%'; + // lightness can be anything from 0 to 100, but probabilities are a bell curve around 50% + const l = ((rand() + rand() + rand() + rand()) * 25) + '%'; + const color = 'hsl(' + h + ',' + s + ',' + l + ')'; + return color; + } + function createImageData(size) { + const width = size; // Only support square icons for now + const height = size; + const dataWidth = Math.ceil(width / 2); + const mirrorWidth = width - dataWidth; + const data = []; + for (let y = 0; y < height; y++) { + let row = []; + for (let x = 0; x < dataWidth; x++) { + // this makes foreground and background color to have a 43% (1/2.3) probability + // spot color has 13% chance + row[x] = Math.floor(rand() * 2.3); + } + const r = row.slice(0, mirrorWidth); + r.reverse(); + row = row.concat(r); + for (let i = 0; i < row.length; i++) { + data.push(row[i]); + } + } + return data; + } + function setCanvas(identicon, imageData, color, scale, bgcolor, spotcolor) { + const width = Math.sqrt(imageData.length); + const size = width * scale; + identicon.width = size; + identicon.style.width = `${size}px`; + identicon.height = size; + identicon.style.height = `${size}px`; + const cc = identicon.getContext('2d'); + cc.fillStyle = bgcolor; + cc.fillRect(0, 0, identicon.width, identicon.height); + cc.fillStyle = color; + for (let i = 0; i < imageData.length; i++) { + // if data is 2, choose spot color, if 1 choose foreground + cc.fillStyle = (imageData[i] === 1) ? color : spotcolor; + // if data is 0, leave the background + if (imageData[i]) { + const row = Math.floor(i / width); + const col = i % width; + cc.fillRect(col * scale, row * scale, scale, scale); + } + } + } + const seed = addressString(address); + seedrand(seed); + const color = createColor(); + const bgcolor = createColor(); + const spotcolor = createColor(); + const imageData = createImageData(8); + const canvas = setCanvas(canvasRef, imageData, color, scale, bgcolor, spotcolor); + return canvas; +} +async function renderBlockieToUrl(address, scale) { + const key = `${address.value}!${scale?.value || 4}`; + const cacheResult = dataURLCache.get(key); + if (cacheResult !== undefined) + return cacheResult; + const future = new Future(); + const element = document.createElement('canvas'); + generateIdenticon(address.value, scale?.value || 4, element); + element.toBlob((blob) => { + if (!blob) + return; + const dataUrl = URL.createObjectURL(blob); + dataURLCache.set(dataUrl, key); + future.resolve(dataUrl); + }); + return await future; +} +export function Blockie(props) { + const dimension = 8 * (props.scale?.value || 4); + const { value: dataURL, waitFor } = useAsyncState(); + useSignalEffect(() => { + props.address.value; + waitFor(async () => renderBlockieToUrl(props.address, props.scale)); + }); + return _jsx("img", { src: dataURL.value.state !== 'resolved' ? 'data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=' : dataURL.value.value, style: { + ...props.style, + width: `${dimension}px`, + height: `${dimension}px`, + minWidth: `${dimension}px`, + minHeight: `${dimension}px`, + } }); +} +//# sourceMappingURL=Blockie.js.map \ No newline at end of file diff --git a/docs/js/components/Blockie.js.map b/docs/js/components/Blockie.js.map new file mode 100644 index 0000000..d7368da --- /dev/null +++ b/docs/js/components/Blockie.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Blockie.js","sourceRoot":"","sources":["../../ts/components/Blockie.tsx"],"names":[],"mappings":"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","sourcesContent":["import { JSX } from 'preact/jsx-runtime'\nimport { ReadonlySignal, Signal, useSignalEffect } from '@preact/signals'\nimport { useAsyncState } from '../library/asyncState.js'\nimport { DataURLCache } from '../library/DataURLCache.js'\n\nconst dataURLCache = new DataURLCache()\n\nclass Future implements PromiseLike {\n\tprivate promise: Promise\n\tprivate resolveFunction: (value: T | PromiseLike) => void\n\tprivate rejectFunction: (reason: Error) => void\n\n\tconstructor() {\n\t\tlet resolveFunction: (value: T | PromiseLike) => void\n\t\tlet rejectFunction: (reason: Error) => void\n\t\tthis.promise = new Promise((resolve: (value: T | PromiseLike) => void, reject: (reason: Error) => void) => {\n\t\t\tresolveFunction = resolve\n\t\t\trejectFunction = reject\n\t\t})\n\t\t// the function passed to the Promise constructor is called before the constructor returns, so we can be sure the resolve and reject functions have been set by here even if the compiler can't verify\n\t\tthis.resolveFunction = resolveFunction!\n\t\tthis.rejectFunction = rejectFunction!\n\t}\n\n\tpublic get asPromise() { return this.promise }\n\n\tpublic readonly then = (\n\t\tonfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null,\n\t\tonrejected?: ((reason: Error) => TResult2 | PromiseLike) | undefined | null\n\t): PromiseLike => {\n\t\treturn this.promise.then(onfulfilled, onrejected)\n\t}\n\n\tpublic readonly resolve = (value: T | PromiseLike) => {\n\t\tthis.resolveFunction!(value)\n\t}\n\n\tpublic readonly reject = (reason: Error) => {\n\t\tthis.rejectFunction!(reason)\n\t}\n}\n\nfunction addressString(address: bigint) {\n\treturn `0x${address.toString(16).padStart(40, '0')}`\n}\n\ninterface BlockieProps {\n\taddress: Signal | ReadonlySignal,\n\tscale?: Signal,\n\tstyle?: JSX.CSSProperties\n}\n\nfunction generateIdenticon(address: bigint, scale: number, canvasRef: HTMLCanvasElement) {\n\t// NOTE -- Majority of this code is referenced from: https://github.com/alexvandesande/blockies\n\t// Mostly to ensure congruence to Ethereum Mist's Identicons\n\n\t// The random number is a js implementation of the Xorshift PRNG\n\tconst randseed = new Array(4) // Xorshift: [x, y, z, w] 32 bit values\n\n\tfunction seedrand(seed: string) {\n\t\tfor (let i = 0; i < randseed.length; i++) {\n\t\t\trandseed[i] = 0\n\t\t}\n\t\tfor (let i = 0; i < seed.length; i++) {\n\t\t\trandseed[i % 4] = ((randseed[i % 4] << 5) - randseed[i % 4]) + seed.charCodeAt(i)\n\t\t}\n\t}\n\n\tfunction rand() {\n\t\t// based on Java's String.hashCode(), expanded to 4 32bit values\n\t\tconst t = randseed[0] ^ (randseed[0] << 11)\n\n\t\trandseed[0] = randseed[1]\n\t\trandseed[1] = randseed[2]\n\t\trandseed[2] = randseed[3]\n\t\trandseed[3] = (randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8))\n\n\t\treturn (randseed[3] >>> 0) / ((1 << 31) >>> 0)\n\t}\n\n\tfunction createColor() {\n\t\t// saturation is the whole color spectrum\n\t\tconst h = Math.floor(rand() * 360)\n\t\t// saturation goes from 40 to 100, it avoids greyish colors\n\t\tconst s = ((rand() * 60) + 40) + '%'\n\t\t// lightness can be anything from 0 to 100, but probabilities are a bell curve around 50%\n\t\tconst l = ((rand() + rand() + rand() + rand()) * 25) + '%'\n\n\t\tconst color = 'hsl(' + h + ',' + s + ',' + l + ')'\n\t\treturn color\n\t}\n\n\tfunction createImageData(size: number) {\n\t\tconst width = size // Only support square icons for now\n\t\tconst height = size\n\n\t\tconst dataWidth = Math.ceil(width / 2)\n\t\tconst mirrorWidth = width - dataWidth\n\n\t\tconst data = []\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tlet row = []\n\t\t\tfor (let x = 0; x < dataWidth; x++) {\n\t\t\t\t// this makes foreground and background color to have a 43% (1/2.3) probability\n\t\t\t\t// spot color has 13% chance\n\t\t\t\trow[x] = Math.floor(rand() * 2.3)\n\t\t\t}\n\t\t\tconst r = row.slice(0, mirrorWidth)\n\t\t\tr.reverse()\n\t\t\trow = row.concat(r)\n\n\t\t\tfor (let i = 0; i < row.length; i++) {\n\t\t\t\tdata.push(row[i])\n\t\t\t}\n\t\t}\n\n\t\treturn data\n\t}\n\n\tfunction setCanvas(identicon: HTMLCanvasElement, imageData: number[], color: string, scale: number, bgcolor: string, spotcolor: string) {\n\t\tconst width = Math.sqrt(imageData.length)\n\t\tconst size = width * scale\n\n\t\tidenticon.width = size\n\t\tidenticon.style.width = `${size}px`\n\n\t\tidenticon.height = size\n\t\tidenticon.style.height = `${size}px`\n\n\t\tconst cc = identicon.getContext('2d')\n\t\tcc!.fillStyle = bgcolor\n\t\tcc!.fillRect(0, 0, identicon.width, identicon.height)\n\t\tcc!.fillStyle = color\n\n\t\tfor (let i = 0; i < imageData.length; i++) {\n\t\t\t// if data is 2, choose spot color, if 1 choose foreground\n\t\t\tcc!.fillStyle = (imageData[i] === 1) ? color : spotcolor\n\n\t\t\t// if data is 0, leave the background\n\t\t\tif (imageData[i]) {\n\t\t\t\tconst row = Math.floor(i / width)\n\t\t\t\tconst col = i % width\n\n\t\t\t\tcc!.fillRect(col * scale, row * scale, scale, scale)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst seed = addressString(address)\n\n\tseedrand(seed)\n\n\tconst color = createColor()\n\tconst bgcolor = createColor()\n\tconst spotcolor = createColor()\n\tconst imageData = createImageData(8)\n\tconst canvas = setCanvas(canvasRef, imageData, color, scale, bgcolor, spotcolor)\n\n\treturn canvas\n}\n\nasync function renderBlockieToUrl(address: Signal, scale: Signal | undefined) {\n\tconst key = `${address.value}!${scale?.value || 4}`\n\tconst cacheResult = dataURLCache.get(key)\n\tif (cacheResult !== undefined) return cacheResult\n\tconst future = new Future()\n\tconst element = document.createElement('canvas')\n\tgenerateIdenticon(address.value, scale?.value || 4, element)\n\telement.toBlob((blob) => {\n\t\tif (!blob) return\n\t\tconst dataUrl = URL.createObjectURL(blob)\n\t\tdataURLCache.set(dataUrl, key)\n\t\tfuture.resolve(dataUrl)\n\t})\n\treturn await future\n}\n\nexport function Blockie(props: BlockieProps) {\n\tconst dimension = 8 * (props.scale?.value || 4)\n\tconst { value: dataURL, waitFor } = useAsyncState()\n\tuseSignalEffect(() => {\n\t\tprops.address.value\n\t\twaitFor(async () => renderBlockieToUrl(props.address, props.scale))\n\t})\n\treturn unknown; +}) => import("preact").JSX.Element; +//# sourceMappingURL=Button.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Button.d.ts.map b/docs/js/components/Button.d.ts.map new file mode 100644 index 0000000..777cf8f --- /dev/null +++ b/docs/js/components/Button.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../ts/components/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAQ1C,eAAO,MAAM,MAAM;cAMR,iBAAiB;;;aAGlB,MAAM,OAAO;kCAOtB,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Button.js b/docs/js/components/Button.js new file mode 100644 index 0000000..c8d4322 --- /dev/null +++ b/docs/js/components/Button.js @@ -0,0 +1,10 @@ +import { jsx as _jsx } from "preact/jsx-runtime"; +const classNames = { + primary: 'h-12 px-4 border border-white/50 bg-gray-500/50 outline-none focus:border-white/90 focus:bg-gray-500/20 flex items-center gap-2 justify-center disabled:opacity-50', + secondary: 'h-12 px-4 border border-white/50 bg-black outline-none focus:border-white/90 focus:bg-gray-500/20 text-white flex items-center gap-2 justify-center disabled:opacity-50', + full: 'px-4 h-16 border border-white/50 text-lg bg-white/10 flex items-center gap-2 justify-center outline-none focus:border-white/90 focus:bg-gray-500 disabled:opacity-50' +}; +export const Button = ({ children, disabled, variant, onClick, }) => { + return (_jsx("button", { onClick: onClick, disabled: disabled ?? false, className: classNames[variant ?? 'primary'], children: children })); +}; +//# sourceMappingURL=Button.js.map \ No newline at end of file diff --git a/docs/js/components/Button.js.map b/docs/js/components/Button.js.map new file mode 100644 index 0000000..adb4480 --- /dev/null +++ b/docs/js/components/Button.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../ts/components/Button.tsx"],"names":[],"mappings":";AAEA,MAAM,UAAU,GAAG;IAClB,OAAO,EAAE,oKAAoK;IAC7K,SAAS,EAAE,yKAAyK;IACpL,IAAI,EAAE,sKAAsK;CAC5K,CAAA;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACtB,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,OAAO,GAMP,EAAE,EAAE;IACJ,OAAO,CACN,iBAAQ,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,IAAI,SAAS,CAAC,YAChG,QAAQ,GACD,CACT,CAAA;AACF,CAAC,CAAA","sourcesContent":["import { ComponentChildren } from 'preact'\n\nconst classNames = {\n\tprimary: 'h-12 px-4 border border-white/50 bg-gray-500/50 outline-none focus:border-white/90 focus:bg-gray-500/20 flex items-center gap-2 justify-center disabled:opacity-50',\n\tsecondary: 'h-12 px-4 border border-white/50 bg-black outline-none focus:border-white/90 focus:bg-gray-500/20 text-white flex items-center gap-2 justify-center disabled:opacity-50',\n\tfull: 'px-4 h-16 border border-white/50 text-lg bg-white/10 flex items-center gap-2 justify-center outline-none focus:border-white/90 focus:bg-gray-500 disabled:opacity-50'\n}\n\nexport const Button = ({\n\tchildren,\n\tdisabled,\n\tvariant,\n\tonClick,\n}: {\n\tchildren: ComponentChildren,\n\tdisabled?: boolean\n\tvariant?: 'primary' | 'secondary' | 'full'\n\tonClick: () => unknown\n}) => {\n\treturn (\n\t\t\n\t)\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/ConfigureFunding.d.ts b/docs/js/components/ConfigureFunding.d.ts new file mode 100644 index 0000000..e233f85 --- /dev/null +++ b/docs/js/components/ConfigureFunding.d.ts @@ -0,0 +1,13 @@ +import { ReadonlySignal, Signal } from '@preact/signals'; +import { JSX } from 'preact/jsx-runtime'; +import { ProviderStore } from '../library/provider.js'; +import { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'; +export declare const ConfigureFunding: ({ provider, appSettings, bundle, fundingAmountMin, signers, blockInfo, }: { + provider: Signal; + bundle: Signal; + signers: Signal; + fundingAmountMin: ReadonlySignal; + blockInfo: Signal; + appSettings: Signal; +}) => JSX.Element; +//# sourceMappingURL=ConfigureFunding.d.ts.map \ No newline at end of file diff --git a/docs/js/components/ConfigureFunding.d.ts.map b/docs/js/components/ConfigureFunding.d.ts.map new file mode 100644 index 0000000..7224fb1 --- /dev/null +++ b/docs/js/components/ConfigureFunding.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ConfigureFunding.d.ts","sourceRoot":"","sources":["../../ts/components/ConfigureFunding.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,cAAc,EAAE,MAAM,EAA2C,MAAM,iBAAiB,CAAA;AAExG,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAIxC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAGtD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAI3E,eAAO,MAAM,gBAAgB;cAQlB,OAAO,aAAa,GAAG,SAAS,CAAC;YACnC,OAAO,MAAM,GAAG,SAAS,CAAC;aACzB,OAAO,OAAO,CAAC;sBACN,eAAe,MAAM,CAAC;eAC7B,OAAO,SAAS,CAAC;iBACf,OAAO,WAAW,CAAC;iBA2FhC,CAAA"} \ No newline at end of file diff --git a/docs/js/components/ConfigureFunding.js b/docs/js/components/ConfigureFunding.js new file mode 100644 index 0000000..b092172 --- /dev/null +++ b/docs/js/components/ConfigureFunding.js @@ -0,0 +1,121 @@ +import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "preact/jsx-runtime"; +import { batch, useComputed, useSignal, useSignalEffect } from '@preact/signals'; +import { EtherSymbol, formatEther, getAddress, JsonRpcProvider } from 'ethers'; +import { NETWORKS } from '../constants.js'; +import { useAsyncState } from '../library/asyncState.js'; +import { getMaxBaseFeeInFutureBlock } from '../library/bundleUtils.js'; +import { addressString } from '../library/utils.js'; +import { EthereumAddress } from '../types/ethereumTypes.js'; +import { Button } from './Button.js'; +import { SingleNotice } from './Warns.js'; +export const ConfigureFunding = ({ provider, appSettings, bundle, fundingAmountMin, signers, blockInfo, }) => { + const signerKeys = useSignal({}); + useSignalEffect(() => { + if (!bundle.value) + signerKeys.value = {}; + }); + if (bundle.peek() && Object.keys(signerKeys.peek()).length === 0) { + signerKeys.value = + bundle.value && Object.keys(signerKeys.peek()).length === 0 + ? bundle.value.uniqueSigners.reduce((curr, address) => { + curr[getAddress(address)] = { input: '', wallet: null }; + return curr; + }, {}) + : {}; + } + blockInfo.subscribe(() => { + if (provider.value && signers.value.burner) { + provider.value.provider.getBalance(signers.value.burner.address).then((balance) => (signers.value.burnerBalance = balance)); + } + }); + function copyBurnerToClipboard() { + if (!signers.value.burner) + return; + navigator.clipboard.writeText(signers.value.burner.address); + } + const showWithdrawModal = useSignal(false); + function openWithdrawModal() { + showWithdrawModal.value = true; + } + return (_jsxs(_Fragment, { children: [_jsx(WithdrawModal, { display: showWithdrawModal, blockInfo, signers, appSettings, provider }), bundle.value && bundle.value.containsFundingTx && signers.value.burner ? (_jsxs("div", { className: 'flex flex-col w-full gap-4', children: [_jsx("h3", { className: 'text-2xl font-semibold', children: "Deposit To Funding Account" }), _jsx("p", { className: 'text-orange-600 font-semibold', children: "This is a temporary account, send only enough needed plus a tiny bit to account for possible rising gas price changes." }), _jsxs("div", { className: 'flex items-center gap-2 flex-wrap', children: [_jsx(Button, { variant: 'secondary', onClick: copyBurnerToClipboard, children: _jsxs(_Fragment, { children: [_jsx("span", { className: 'text-xs sm:text-base', children: signers.value.burner.address }), _jsx("svg", { className: 'h-8 inline-block', "aria-hidden": 'true', fill: 'none', stroke: 'currentColor', "stroke-width": '1.5', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', children: _jsx("path", { d: 'M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6', "stroke-linecap": 'round', "stroke-linejoin": 'round' }) })] }) }), _jsx(Button, { variant: 'primary', onClick: openWithdrawModal, children: _jsxs("span", { className: 'flex gap-2 text-sm items-center', children: ["Withdraw ETH", _jsx("svg", { class: 'h-8 inline-block', "aria-hidden": 'true', fill: 'none', stroke: 'currentColor', "stroke-width": '1.5', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', children: _jsx("path", { d: 'M8.25 9.75h4.875a2.625 2.625 0 010 5.25H12M8.25 9.75L10.5 7.5M8.25 9.75L10.5 12m9-7.243V21.75l-3.75-1.5-3.75 1.5-3.75-1.5-3.75 1.5V4.757c0-1.108.806-2.057 1.907-2.185a48.507 48.507 0 0111.186 0c1.1.128 1.907 1.077 1.907 2.185z', "stroke-linecap": 'round', "stroke-linejoin": 'round' }) })] }) })] }), _jsxs("p", { className: 'font-semibold sm:text-lg', children: ["Wallet Balance: ", _jsxs("span", { className: 'font-medium font-mono', children: [EtherSymbol, formatEther(signers.value.burnerBalance)] }), _jsx("br", {}), "Minimum Required Balance: ", _jsxs("span", { className: 'font-medium font-mono', children: [EtherSymbol, formatEther(fundingAmountMin.value)] })] })] })) : null] })); +}; +const WithdrawModal = ({ display, blockInfo, signers, provider }) => { + if (!display.value) + return null; + const recipientAddress = useSignal({ input: '' }); + const inputStyle = useComputed(() => `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${recipientAddress.value.address ? 'border-green-400' : (recipientAddress.value.input ? 'border-red-400' : 'border-white/50 focus-within:border-white/80')}`); + function parseInput(input) { + const address = EthereumAddress.safeParse(input); + recipientAddress.value = { input, address: address.success ? address.value : undefined }; + } + const withdrawAmount = useComputed(() => { + let maxFeePerGas = getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, 5n) + blockInfo.value.priorityFee; + let fee = maxFeePerGas * 21000n; + let amount = signers.value.burnerBalance - fee; + return { amount, fee, maxFeePerGas }; + }); + const { value: signedMessage, waitFor } = useAsyncState(); + // Default check if we know the network, can also switch to true if sending to known RPC fails + const useBrowserProvider = useSignal(provider.value && !(provider.value.chainId.toString(10) in NETWORKS) ? true : false); + const blockExplorer = useComputed(() => { + if (provider.value) { + const chainId = provider.value.chainId.toString(10); + return chainId in NETWORKS ? NETWORKS[chainId].blockExplorer : undefined; + } + return undefined; + }); + function withdraw() { + waitFor(async () => { + if (withdrawAmount.value.amount <= 0n) + throw 'Funding account\'s balance is to small to withdraw'; + if (!signers.value.burner) + throw 'No funding account found'; + if (!provider.value) + throw 'User not connected'; + if (!recipientAddress.value.address) + throw 'No recipient provided'; + // Worst case scenario, attempt to send via browser wallet if no NETWORK config for chainId or previous error sending to known RPC + if (useBrowserProvider.value === true) { + try { + const burnerWithBrowserProvider = signers.value.burner.connect(provider.value.provider); + const txInput = await burnerWithBrowserProvider.populateTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas }); + const tx = await burnerWithBrowserProvider.signTransaction(txInput); + const txHash = await provider.value.provider.send('eth_sendRawTransaction', [tx]); + return txHash; + } + catch (error) { + throw error; + } + } + // If user is on network that is in NETWORK, send via ethRpc + const chainId = provider.value.chainId.toString(10); + if (!(chainId in NETWORKS)) { + useBrowserProvider.value = true; + throw 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.'; + } + const fundingWithProvider = signers.value.burner.connect(new JsonRpcProvider(NETWORKS[chainId].rpcUrl)); + try { + const tx = await fundingWithProvider.sendTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas }); + fundingWithProvider.provider?.destroy(); + return tx.hash; + } + catch (error) { + console.warn('Error sending burner withdraw tx to known RPC:', error); + fundingWithProvider.provider?.destroy(); + useBrowserProvider.value = true; + throw 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.'; + } + }); + } + function close() { + batch(() => { + display.value = false; + recipientAddress.value = { input: '' }; + signedMessage.value.state = 'inactive'; + }); + } + return (_jsx("div", { onClick: close, className: 'bg-white/10 w-full h-full inset-0 fixed p-4 flex flex-col items-center md:pt-24', children: _jsxs("div", { class: 'h-max w-full max-w-xl px-8 py-4 flex flex-col gap-4 bg-black', onClick: (e) => e.stopPropagation(), children: [_jsx("h2", { className: 'text-xl font-semibold', children: "Withdraw From Funding Account" }), _jsxs("div", { className: inputStyle.value, children: [_jsx("span", { className: 'text-sm text-gray-500', children: "ETH Recipient" }), _jsx("input", { onInput: (e) => parseInput(e.currentTarget.value), type: 'text', className: 'bg-transparent outline-none placeholder:text-gray-600', placeholder: '0x...' })] }), withdrawAmount.value.amount > 0n + ? (_jsxs("p", { children: ["Withdraw ", EtherSymbol, " ", formatEther(withdrawAmount.value.amount), " + ", EtherSymbol, " ", formatEther(withdrawAmount.value.fee), " fee"] })) + : (_jsxs("p", { children: ["Transfer fee (", EtherSymbol, " ", formatEther(withdrawAmount.value.fee), ") is more than funding account balance"] })), _jsx("div", { className: 'flex gap-2', children: _jsx(Button, { onClick: withdraw, variant: 'primary', children: "Withdraw" }) }), _jsx("p", { children: signedMessage.value.state === 'rejected' ? _jsx(SingleNotice, { variant: 'error', description: signedMessage.value.error.message, title: 'Error Withdrawing' }) : '' }), _jsx("p", { children: signedMessage.value.state === 'resolved' ? _jsx(SingleNotice, { variant: 'success', description: blockExplorer.value ? _jsxs("span", { children: ["Transaction submitted with TX Hash ", _jsx("a", { className: 'hover:underline', href: `${blockExplorer.value}tx/${signedMessage.value.value}`, target: '_blank', children: signedMessage.value.value })] }) : _jsxs("span", { children: ["Transaction submitted with TX Hash ", signedMessage.value.value] }), title: 'Transaction Submitted' }) : '' })] }) })); +}; +//# sourceMappingURL=ConfigureFunding.js.map \ No newline at end of file diff --git a/docs/js/components/ConfigureFunding.js.map b/docs/js/components/ConfigureFunding.js.map new file mode 100644 index 0000000..5a23724 --- /dev/null +++ b/docs/js/components/ConfigureFunding.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ConfigureFunding.js","sourceRoot":"","sources":["../../ts/components/ConfigureFunding.tsx"],"names":[],"mappings":"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","sourcesContent":["import { batch, ReadonlySignal, Signal, useComputed, useSignal, useSignalEffect } from '@preact/signals'\nimport { EtherSymbol, formatEther, getAddress, JsonRpcProvider, Wallet } from 'ethers'\nimport { JSX } from 'preact/jsx-runtime'\nimport { NETWORKS } from '../constants.js'\nimport { useAsyncState } from '../library/asyncState.js'\nimport { getMaxBaseFeeInFutureBlock } from '../library/bundleUtils.js'\nimport { ProviderStore } from '../library/provider.js'\nimport { addressString } from '../library/utils.js'\nimport { EthereumAddress } from '../types/ethereumTypes.js'\nimport { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'\nimport { Button } from './Button.js'\nimport { SingleNotice } from './Warns.js'\n\nexport const ConfigureFunding = ({\n\tprovider,\n\tappSettings,\n\tbundle,\n\tfundingAmountMin,\n\tsigners,\n\tblockInfo,\n}: {\n\tprovider: Signal\n\tbundle: Signal\n\tsigners: Signal\n\tfundingAmountMin: ReadonlySignal\n\tblockInfo: Signal,\n\tappSettings: Signal\n}) => {\n\tconst signerKeys = useSignal<{\n\t\t[address: string]: { input: string; wallet: Wallet | null }\n\t}>({})\n\n\tuseSignalEffect(() => {\n\t\tif (!bundle.value) signerKeys.value = {}\n\t})\n\n\tif (bundle.peek() && Object.keys(signerKeys.peek()).length === 0) {\n\t\tsignerKeys.value =\n\t\t\tbundle.value && Object.keys(signerKeys.peek()).length === 0\n\t\t\t\t? bundle.value.uniqueSigners.reduce(\n\t\t\t\t\t(\n\t\t\t\t\t\tcurr: {\n\t\t\t\t\t\t\t[address: string]: { input: string; wallet: Wallet | null }\n\t\t\t\t\t\t},\n\t\t\t\t\t\taddress,\n\t\t\t\t\t) => {\n\t\t\t\t\t\tcurr[getAddress(address)] = { input: '', wallet: null }\n\t\t\t\t\t\treturn curr\n\t\t\t\t\t},\n\t\t\t\t\t{},\n\t\t\t\t)\n\t\t\t\t: {}\n\t}\n\n\tblockInfo.subscribe(() => {\n\t\tif (provider.value && signers.value.burner) {\n\t\t\tprovider.value.provider.getBalance(signers.value.burner.address).then((balance) => (signers.value.burnerBalance = balance))\n\t\t}\n\t})\n\n\tfunction copyBurnerToClipboard() {\n\t\tif (!signers.value.burner) return\n\t\tnavigator.clipboard.writeText(signers.value.burner.address)\n\t}\n\n\tconst showWithdrawModal = useSignal(false)\n\n\tfunction openWithdrawModal() {\n\t\tshowWithdrawModal.value = true\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t{bundle.value && bundle.value.containsFundingTx && signers.value.burner ? (\n\t\t\t\t
\n\t\t\t\t\t

Deposit To Funding Account

\n\t\t\t\t\t

This is a temporary account, send only enough needed plus a tiny bit to account for possible rising gas price changes.

\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t

\n\t\t\t\t\t\tWallet Balance: {EtherSymbol}{formatEther(signers.value.burnerBalance)}\n\t\t\t\t\t\t
\n\t\t\t\t\t\tMinimum Required Balance: {EtherSymbol}{formatEther(fundingAmountMin.value)}\n\t\t\t\t\t

\n\t\t\t\t
\n\t\t\t) : null}\n\t\t\n\t)\n}\n\nconst WithdrawModal = ({ display, blockInfo, signers, provider }: { display: Signal, \tprovider: Signal, signers: Signal, blockInfo: Signal }) => {\n\tif (!display.value) return null\n\n\tconst recipientAddress = useSignal<{ input: string, address?: EthereumAddress }>({ input: '' })\n\tconst inputStyle = useComputed(() => `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${recipientAddress.value.address ? 'border-green-400' : (recipientAddress.value.input ? 'border-red-400' : 'border-white/50 focus-within:border-white/80')}`)\n\tfunction parseInput(input: string) {\n\t\tconst address = EthereumAddress.safeParse(input)\n\t\trecipientAddress.value = { input, address: address.success ? address.value : undefined }\n\t}\n\n\tconst withdrawAmount = useComputed(() => {\n\t\tlet maxFeePerGas = getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, 5n) + blockInfo.value.priorityFee;\n\t\tlet fee = maxFeePerGas * 21000n\n\t\tlet amount = signers.value.burnerBalance - fee\n\t\treturn { amount, fee, maxFeePerGas }\n\t})\n\n\tconst { value: signedMessage, waitFor } = useAsyncState()\n\n\t// Default check if we know the network, can also switch to true if sending to known RPC fails\n\tconst useBrowserProvider = useSignal(provider.value && !(provider.value.chainId.toString(10) in NETWORKS) ? true : false)\n\n\tconst blockExplorer = useComputed(() => {\n\t\tif (provider.value) {\n\t\t\tconst chainId = provider.value.chainId.toString(10)\n\t\t\treturn chainId in NETWORKS ? NETWORKS[chainId].blockExplorer : undefined\n\t\t}\n\t\treturn undefined\n\t})\n\n\tfunction withdraw() {\n\t\twaitFor(async () => {\n\t\t\tif (withdrawAmount.value.amount <= 0n) throw 'Funding account\\'s balance is to small to withdraw'\n\t\t\tif (!signers.value.burner) throw 'No funding account found'\n\t\t\tif (!provider.value) throw 'User not connected'\n\t\t\tif (!recipientAddress.value.address) throw 'No recipient provided'\n\n\t\t\t// Worst case scenario, attempt to send via browser wallet if no NETWORK config for chainId or previous error sending to known RPC\n\t\t\tif (useBrowserProvider.value === true) {\n\t\t\t\ttry {\n\t\t\t\t\tconst burnerWithBrowserProvider = signers.value.burner.connect(provider.value.provider)\n\t\t\t\t\tconst txInput = await burnerWithBrowserProvider.populateTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas })\n\t\t\t\t\tconst tx = await burnerWithBrowserProvider.signTransaction(txInput)\n\t\t\t\t\tconst txHash = await provider.value.provider.send('eth_sendRawTransaction', [tx])\n\t\t\t\t\treturn txHash as string\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If user is on network that is in NETWORK, send via ethRpc\n\t\t\tconst chainId = provider.value.chainId.toString(10)\n\t\t\tif (!(chainId in NETWORKS)) {\n\t\t\t\tuseBrowserProvider.value = true\n\t\t\t\tthrow 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.'\n\t\t\t}\n\n\t\t\tconst fundingWithProvider = signers.value.burner.connect(new JsonRpcProvider(NETWORKS[chainId].rpcUrl))\n\t\t\ttry {\n\t\t\t\tconst tx = await fundingWithProvider.sendTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas })\n\t\t\t\tfundingWithProvider.provider?.destroy()\n\t\t\t\treturn tx.hash\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn('Error sending burner withdraw tx to known RPC:', error)\n\t\t\t\tfundingWithProvider.provider?.destroy()\n\t\t\t\tuseBrowserProvider.value = true\n\t\t\t\tthrow 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.'\n\t\t\t}\n\t\t})\n\t}\n\n\tfunction close() {\n\t\tbatch(() => {\n\t\t\tdisplay.value = false\n\t\t\trecipientAddress.value = { input: '' }\n\t\t\tsignedMessage.value.state = 'inactive'\n\t\t})\n\t}\n\n\treturn (\n\t\t
\n\t\t\t
e.stopPropagation()}>\n\t\t\t\t

Withdraw From Funding Account

\n\t\t\t\t
\n\t\t\t\t\tETH Recipient\n\t\t\t\t\t) => parseInput(e.currentTarget.value)} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='0x...' />\n\t\t\t\t
\n\t\t\t\t{withdrawAmount.value.amount > 0n\n\t\t\t\t\t? (

Withdraw {EtherSymbol} {formatEther(withdrawAmount.value.amount)} + {EtherSymbol} {formatEther(withdrawAmount.value.fee)} fee

)\n\t\t\t\t\t: (

Transfer fee ({EtherSymbol} {formatEther(withdrawAmount.value.fee)}) is more than funding account balance

)}\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t\t

{signedMessage.value.state === 'rejected' ? : ''}

\n\t\t\t\t

{signedMessage.value.state === 'resolved' ? Transaction submitted with TX Hash {signedMessage.value.value} : Transaction submitted with TX Hash {signedMessage.value.value}} title='Transaction Submitted' /> : ''}

\n\t\t\t
\n\t\t
\n\t)\n}\n\n"]} \ No newline at end of file diff --git a/docs/js/components/ConfigureKeys.d.ts b/docs/js/components/ConfigureKeys.d.ts new file mode 100644 index 0000000..241f1a0 --- /dev/null +++ b/docs/js/components/ConfigureKeys.d.ts @@ -0,0 +1,11 @@ +import { Signal } from '@preact/signals'; +import { JSX } from 'preact/jsx-runtime'; +import { ProviderStore } from '../library/provider.js'; +import { BlockInfo, Bundle, Signers } from '../types/types.js'; +export declare const ConfigureKeys: ({ provider, bundle, signers, blockInfo, }: { + provider: Signal; + bundle: Signal; + signers: Signal; + blockInfo: Signal; +}) => JSX.Element; +//# sourceMappingURL=ConfigureKeys.d.ts.map \ No newline at end of file diff --git a/docs/js/components/ConfigureKeys.d.ts.map b/docs/js/components/ConfigureKeys.d.ts.map new file mode 100644 index 0000000..bba01c2 --- /dev/null +++ b/docs/js/components/ConfigureKeys.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ConfigureKeys.d.ts","sourceRoot":"","sources":["../../ts/components/ConfigureKeys.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAA8B,MAAM,iBAAiB,CAAA;AAE3E,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE9D,eAAO,MAAM,aAAa;cAMf,OAAO,aAAa,GAAG,SAAS,CAAC;YACnC,OAAO,MAAM,GAAG,SAAS,CAAC;aACzB,OAAO,OAAO,CAAC;eACb,OAAO,SAAS,CAAC;iBAwE5B,CAAA"} \ No newline at end of file diff --git a/docs/js/components/ConfigureKeys.js b/docs/js/components/ConfigureKeys.js new file mode 100644 index 0000000..646c53d --- /dev/null +++ b/docs/js/components/ConfigureKeys.js @@ -0,0 +1,54 @@ +import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime"; +import { batch, useSignal, useSignalEffect } from '@preact/signals'; +import { Wallet } from 'ethers'; +export const ConfigureKeys = ({ provider, bundle, signers, blockInfo, }) => { + const signerKeys = useSignal({}); + useSignalEffect(() => { + if (!bundle.value) + signerKeys.value = {}; + if (bundle.value && bundle.value.uniqueSigners.join() !== Object.keys(signerKeys.value).join()) { + signerKeys.value = bundle.value.uniqueSigners.reduce((curr, address) => { + curr[address] = { input: '', wallet: null }; + return curr; + }, {}); + } + }); + blockInfo.subscribe(() => { + if (provider.value && signers.value.burner) { + provider.value.provider.getBalance(signers.value.burner.address).then((balance) => (signers.value.burnerBalance = balance)); + } + }); + function tryUpdateSigners(address, privateKey) { + batch(() => { + try { + const wallet = new Wallet(privateKey); + signerKeys.value = { + ...signerKeys.peek(), + [address]: { + wallet: wallet.address === address ? wallet : null, + input: privateKey, + }, + }; + } + catch { + signerKeys.value = { + ...signerKeys.peek(), + [address]: { wallet: null, input: privateKey }, + }; + } + if (Object.values(signerKeys.value).filter(({ wallet }) => !wallet).length === 0) { + signers.value = { + ...signers.peek(), + bundleSigners: Object.values(signerKeys.peek()).reduce((acc, wallet) => { + if (wallet.wallet) { + acc[wallet.wallet.address] = wallet.wallet; + } + return acc; + }, {}), + }; + } + }); + } + return (_jsxs("div", { className: 'flex flex-col w-full gap-4', children: [_jsx("h3", { className: 'text-2xl font-semibold', children: "Enter Private Keys For Signing Accounts" }), Object.keys(signerKeys.value).map((address) => (_jsxs("div", { className: `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${signerKeys.value[address].wallet ? 'border-green-400' : (signerKeys.peek()[address].input ? 'border-red-400' : 'border-white/50 focus-within:border-white/80')}`, children: [_jsx("span", { className: 'text-sm text-gray-500', children: address }), _jsx("input", { onInput: (e) => tryUpdateSigners(address, e.currentTarget.value), value: signerKeys.value[address].input, type: 'text', className: 'bg-transparent outline-none placeholder:text-gray-600', placeholder: `Enter private key for account` })] })))] })); +}; +//# sourceMappingURL=ConfigureKeys.js.map \ No newline at end of file diff --git a/docs/js/components/ConfigureKeys.js.map b/docs/js/components/ConfigureKeys.js.map new file mode 100644 index 0000000..3266505 --- /dev/null +++ b/docs/js/components/ConfigureKeys.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ConfigureKeys.js","sourceRoot":"","sources":["../../ts/components/ConfigureKeys.tsx"],"names":[],"mappings":"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","sourcesContent":["import { batch, Signal, useSignal, useSignalEffect } from '@preact/signals'\nimport { Wallet } from 'ethers'\nimport { JSX } from 'preact/jsx-runtime'\nimport { ProviderStore } from '../library/provider.js'\nimport { BlockInfo, Bundle, Signers } from '../types/types.js'\n\nexport const ConfigureKeys = ({\n\tprovider,\n\tbundle,\n\tsigners,\n\tblockInfo,\n}: {\n\tprovider: Signal\n\tbundle: Signal\n\tsigners: Signal\n\tblockInfo: Signal\n}) => {\n\tconst signerKeys = useSignal<{\n\t\t[address: string]: { input: string; wallet: Wallet | null }\n\t}>({})\n\n\tuseSignalEffect(() => {\n\t\tif (!bundle.value) signerKeys.value = {}\n\t\tif (bundle.value && bundle.value.uniqueSigners.join() !== Object.keys(signerKeys.value).join()) {\n\t\t\tsignerKeys.value = bundle.value.uniqueSigners.reduce((\n\t\t\t\t\tcurr: {\n\t\t\t\t\t\t[address: string]: { input: string; wallet: Wallet | null }\n\t\t\t\t\t},\n\t\t\t\t\taddress,\n\t\t\t\t) => {\n\t\t\t\t\tcurr[address] = { input: '', wallet: null }\n\t\t\t\t\treturn curr\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t)\n\t\t}\n\t})\n\n\tblockInfo.subscribe(() => {\n\t\tif (provider.value && signers.value.burner) {\n\t\t\tprovider.value.provider.getBalance(signers.value.burner.address).then((balance) => (signers.value.burnerBalance = balance))\n\t\t}\n\t})\n\n\tfunction tryUpdateSigners(address: string, privateKey: string) {\n\t\tbatch(() => {\n\t\t\ttry {\n\t\t\t\tconst wallet = new Wallet(privateKey)\n\n\t\t\t\tsignerKeys.value = {\n\t\t\t\t\t...signerKeys.peek(),\n\t\t\t\t\t[address]: {\n\t\t\t\t\t\twallet: wallet.address === address ? wallet : null,\n\t\t\t\t\t\tinput: privateKey,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tsignerKeys.value = {\n\t\t\t\t\t...signerKeys.peek(),\n\t\t\t\t\t[address]: { wallet: null, input: privateKey },\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Object.values(signerKeys.value).filter(({ wallet }) => !wallet).length === 0) {\n\t\t\t\tsigners.value = {\n\t\t\t\t\t...signers.peek(),\n\t\t\t\t\tbundleSigners: Object.values(signerKeys.peek()).reduce((acc: { [account: string]: Wallet }, wallet) => {\n\t\t\t\t\t\tif (wallet.wallet) {\n\t\t\t\t\t\t\tacc[wallet.wallet.address] = wallet.wallet\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn acc\n\t\t\t\t\t}, {}),\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\treturn (\n\t\t
\n\t\t\t

Enter Private Keys For Signing Accounts

\n\t\t\t{Object.keys(signerKeys.value).map((address) => (\n\t\t\t\t
\n\t\t\t\t\t{address}\n\t\t\t\t\t) => tryUpdateSigners(address, e.currentTarget.value)} value={signerKeys.value[address].input} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder={`Enter private key for account`} />\n\t\t\t\t
\n\t\t\t))}\n\t\t
\n\t)\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Footer.d.ts b/docs/js/components/Footer.d.ts new file mode 100644 index 0000000..60f5dad --- /dev/null +++ b/docs/js/components/Footer.d.ts @@ -0,0 +1,2 @@ +export declare const Footer: () => import("preact").JSX.Element; +//# sourceMappingURL=Footer.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Footer.d.ts.map b/docs/js/components/Footer.d.ts.map new file mode 100644 index 0000000..6339e61 --- /dev/null +++ b/docs/js/components/Footer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../ts/components/Footer.tsx"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,oCAkBlB,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Footer.js b/docs/js/components/Footer.js new file mode 100644 index 0000000..92e4db6 --- /dev/null +++ b/docs/js/components/Footer.js @@ -0,0 +1,3 @@ +import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime"; +export const Footer = () => (_jsxs("footer", { className: 'mt-auto w-full', children: [_jsxs("div", { className: 'flex flex-col sm:flex-row w-full gap-6 justify-around items-center', children: [_jsxs("div", { className: 'flex flex-col gap-2', children: [_jsx("h2", { className: 'font-semibold', children: "Contact" }), _jsx("a", { href: 'https://discord.com/invite/aCSKcvf5VW', target: '_blank', className: 'hover:underline text-gray-500', children: "Discord" }), _jsx("a", { href: 'https://twitter.com/DarkFlorist', target: '_blank', className: 'hover:underline text-gray-500', children: "Twitter" }), _jsx("a", { href: 'https://github.com/DarkFlorist/bouquet', target: '_blank', className: 'hover:underline text-gray-500', children: "Github" })] }), _jsxs("div", { className: 'flex flex-col gap-2', children: [_jsx("h2", { className: 'font-semibold', children: "Our other tools" }), _jsx("a", { href: 'https://dark.florist/', className: 'hover:underline text-gray-500', children: "The Interceptor" }), _jsx("a", { href: 'https://lunaria.dark.florist/', className: 'hover:underline text-gray-500', children: "Lunaria" }), _jsx("a", { href: 'https://nftsender.dark.florist/', className: 'hover:underline text-gray-500', children: "NFT Sender" })] })] }), _jsx("div", { className: 'font-xs py-8 sm:py-6 flex items-center justify-center', children: _jsxs("p", { className: 'hidden sm:block', children: ["\uD83D\uDC90 Bouquet by ", _jsx("a", { href: 'https://dark.florist', className: 'hover:underline', children: "DarkFlorist" })] }) })] })); +//# sourceMappingURL=Footer.js.map \ No newline at end of file diff --git a/docs/js/components/Footer.js.map b/docs/js/components/Footer.js.map new file mode 100644 index 0000000..ae3137b --- /dev/null +++ b/docs/js/components/Footer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Footer.js","sourceRoot":"","sources":["../../ts/components/Footer.tsx"],"names":[],"mappings":";AAAA,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,CAC3B,kBAAQ,SAAS,EAAC,gBAAgB,aACjC,eAAK,SAAS,EAAC,oEAAoE,aAClF,eAAK,SAAS,EAAC,qBAAqB,aACnC,aAAI,SAAS,EAAC,eAAe,wBAAa,EAC1C,YAAG,IAAI,EAAC,uCAAuC,EAAC,MAAM,EAAC,QAAQ,EAAC,SAAS,EAAC,+BAA+B,wBAAY,EACrH,YAAG,IAAI,EAAC,iCAAiC,EAAC,MAAM,EAAC,QAAQ,EAAC,SAAS,EAAC,+BAA+B,wBAAY,EAC/G,YAAG,IAAI,EAAC,wCAAwC,EAAC,MAAM,EAAC,QAAQ,EAAC,SAAS,EAAC,+BAA+B,uBAAW,IAChH,EACN,eAAK,SAAS,EAAC,qBAAqB,aACnC,aAAI,SAAS,EAAC,eAAe,gCAAqB,EAClD,YAAG,IAAI,EAAC,uBAAuB,EAAC,SAAS,EAAC,+BAA+B,gCAAoB,EAC7F,YAAG,IAAI,EAAC,+BAA+B,EAAC,SAAS,EAAC,+BAA+B,wBAAY,EAC7F,YAAG,IAAI,EAAC,iCAAiC,EAAC,SAAS,EAAC,+BAA+B,2BAAe,IAC7F,IACD,EACN,cAAK,SAAS,EAAC,uDAAuD,YAAC,aAAG,SAAS,EAAC,iBAAiB,yCAAe,YAAG,IAAI,EAAC,sBAAsB,EAAC,SAAS,EAAC,iBAAiB,4BAAgB,IAAI,GAAM,IAChM,CACT,CAAA","sourcesContent":["export const Footer = () => (\n\t\n)\n"]} \ No newline at end of file diff --git a/docs/js/components/Import.d.ts b/docs/js/components/Import.d.ts new file mode 100644 index 0000000..3f2bd89 --- /dev/null +++ b/docs/js/components/Import.d.ts @@ -0,0 +1,20 @@ +import { Signal } from '@preact/signals'; +import { ProviderStore } from '../library/provider.js'; +import { AppSettings, Bundle, Signers } from '../types/types.js'; +export declare function importFromInterceptor(bundle: Signal, provider: Signal, blockInfo: Signal<{ + blockNumber: bigint; + baseFee: bigint; + priorityFee: bigint; +}>, appSettings: Signal, signers: Signal | undefined): Promise; +export declare const Import: ({ bundle, provider, blockInfo, signers, appSettings, }: { + bundle: Signal; + provider: Signal; + blockInfo: Signal<{ + blockNumber: bigint; + baseFee: bigint; + priorityFee: bigint; + }>; + signers: Signal; + appSettings: Signal; +}) => import("preact").JSX.Element; +//# sourceMappingURL=Import.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Import.d.ts.map b/docs/js/components/Import.d.ts.map new file mode 100644 index 0000000..170e82f --- /dev/null +++ b/docs/js/components/Import.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Import.d.ts","sourceRoot":"","sources":["../../ts/components/Import.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAa,MAAM,iBAAiB,CAAA;AAG1D,OAAO,EAA0B,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAG9E,OAAO,EAAE,WAAW,EAAE,MAAM,EAAa,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAO3E,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,EAClC,QAAQ,EAAE,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,EAC3C,SAAS,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;CACnB,CAAC,EACF,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,EAChC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,SAAS,iBA6EpC;AAED,eAAO,MAAM,MAAM;YAOV,OAAO,MAAM,GAAG,SAAS,CAAC;cACxB,OAAO,aAAa,GAAG,SAAS,CAAC;eAChC,OAAO;QACjB,WAAW,EAAE,MAAM,CAAA;QACnB,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;KACnB,CAAC;aACO,OAAO,OAAO,CAAC;iBACX,OAAO,WAAW,CAAC;kCAqD/B,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Import.js b/docs/js/components/Import.js new file mode 100644 index 0000000..be2dbdc --- /dev/null +++ b/docs/js/components/Import.js @@ -0,0 +1,99 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime"; +import { batch, useSignal } from '@preact/signals'; +import { useState } from 'preact/hooks'; +import { parseEther } from 'ethers'; +import { connectBrowserProvider } from '../library/provider.js'; +import { GetSimulationStackReply } from '../types/interceptorTypes.js'; +import { Button } from './Button.js'; +import { serialize } from '../types/types.js'; +import { TransactionList } from '../types/bouquetTypes.js'; +import { ImportModal } from './ImportModal.js'; +import { SingleNotice } from './Warns.js'; +import { addressString } from '../library/utils.js'; +export async function importFromInterceptor(bundle, provider, blockInfo, appSettings, signers) { + if (!window.ethereum || !window.ethereum.request) + throw Error('No Ethereum wallet detected'); + connectBrowserProvider(provider, blockInfo, signers, appSettings); + const { payload } = await window.ethereum + .request({ + method: 'interceptor_getSimulationStack', + params: ['1.0.0'], + }) + .catch((err) => { + if (err?.code === -32601) { + throw new Error('Wallet does not support returning simulations'); + } + else { + throw new Error(`Unknown Error: ${JSON.stringify(err)}`); + } + }); + const tryParse = GetSimulationStackReply.safeParse(payload); + if (!tryParse.success) + throw new Error('Wallet does not support returning simulations'); + if (tryParse.value.length === 0) + throw new Error('You have no transactions on your simulation'); + const converted = TransactionList.safeParse(serialize(GetSimulationStackReply, tryParse.value).map(({ from, to, value, input, gasLimit, chainId }) => ({ from, to, value, input, gasLimit, chainId }))); + if (!converted.success) + throw new Error('Malformed simulation stack'); + if (converted.value.length >= 2 && converted.value[0].to === converted.value[1].from && converted.value[0].value === parseEther('200000')) { + const fundingAddr = converted.value[0].from; + converted.value = converted.value.map(tx => tx.from === fundingAddr ? { ...tx, from: 'FUNDING' } : tx); + } + const uniqueToAddresses = [...new Set(converted.value.map(({ from }) => from))]; + const containsFundingTx = uniqueToAddresses.includes('FUNDING'); + const uniqueSigners = uniqueToAddresses.filter((address) => address !== 'FUNDING').map(address => addressString(address)); + const totalGas = converted.value.reduce((sum, tx) => tx.gasLimit + sum, 0n); + // Take addresses that recieved funding, determine spend deficit - gas fees + const fundingRecipients = new Set(converted.value.reduce((result, tx) => (tx.to && tx.from === 'FUNDING' ? [...result, tx.to] : result), [])); + const spenderDeficits = tryParse.value.reduce((amounts, tx) => { + if (!fundingRecipients.has(tx.from)) + return amounts; + const receipientBalanceChanges = tx.balanceChanges.filter(x => x.address === tx.from); + const consumed = tx.value; + // Rebate is the difference between balance change and consume amount (if there were any internal transactions sending ETH back), ignore gas fees + const balanceChange = receipientBalanceChanges.reduce((result, balanceChange) => result + balanceChange.after - balanceChange.before, 0n); + const rebate = balanceChange + consumed + tx.maxPriorityFeePerGas * tx.gasSpent; + // Calcuate current deficit + if (tx.from.toString() in amounts) { + // If credit, deduct current credit from new consumption, or cancel out new consumption and open credit - whichever is smaller + if (amounts[tx.from.toString()].credit > 0n) { + if (amounts[tx.from.toString()].credit <= consumed) { + amounts[tx.from.toString()].deficit += consumed - amounts[tx.from.toString()].credit; + amounts[tx.from.toString()].credit = rebate; + } + else { + // If consumed less than current rebates, deficit does not increase. + amounts[tx.from.toString()].credit += rebate - consumed; + } + } + } + else { + amounts[tx.from.toString()] = { deficit: consumed, credit: rebate }; + } + return amounts; + }, {}); + const inputValue = Object.values(spenderDeficits).reduce((sum, spender) => spender.deficit + sum, 0n); + // Copy value and set, input of funding to inputValue + const transactions = [...converted.value]; + if (containsFundingTx) { + transactions[0] = { ...transactions[0], value: inputValue }; + } + localStorage.setItem('payload', JSON.stringify(TransactionList.serialize(transactions))); + bundle.value = { transactions, containsFundingTx, uniqueSigners, totalGas, inputValue }; +} +export const Import = ({ bundle, provider, blockInfo, signers, appSettings, }) => { + const showImportModal = useSignal(false); + const [error, setError] = useState(undefined); + const clearPayload = () => { + batch(() => { + bundle.value = undefined; + localStorage.removeItem('payload'); + signers.value.bundleSigners = {}; + setError(''); + // Keep burner wallet as long as it has funds, should clear is later if there is left over dust but not needed. + // if (fundingAccountBalance.value === 0n) signers.value.burner = undefined + }); + }; + return (_jsxs(_Fragment, { children: [showImportModal.value ? _jsx(ImportModal, { bundle: bundle, clearError: () => setError(''), display: showImportModal }) : null, _jsxs("h2", { className: 'font-bold text-2xl', children: [_jsx("span", { class: 'text-gray-500', children: "1." }), " Import"] }), _jsxs("div", { className: 'flex flex-col w-full gap-6', children: [_jsxs("div", { className: 'flex flex-col sm:flex-row gap-4', children: [_jsx(Button, { onClick: () => importFromInterceptor(bundle, provider, blockInfo, appSettings, signers).then(() => setError(undefined)).catch((err) => setError(err.message)), children: "Import Payload from The Interceptor" }), _jsx(Button, { onClick: () => showImportModal.value = true, children: "Import From JSON" }), bundle.value ? (_jsx(Button, { variant: 'secondary', onClick: clearPayload, children: "Reset" })) : null] }), error ? _jsx(SingleNotice, { variant: 'error', title: 'Could Not Import Transactions', description: error }) : null, error && error === 'Wallet does not support returning simulations' ? (_jsxs("h3", { className: 'text-xl', children: ["Don't have The Interceptor Installed? Install it here", ' ', _jsx("a", { className: 'font-bold text-accent underline', href: 'https://dark.florist', children: "here" }), "."] })) : ('')] })] })); +}; +//# sourceMappingURL=Import.js.map \ No newline at end of file diff --git a/docs/js/components/Import.js.map b/docs/js/components/Import.js.map new file mode 100644 index 0000000..0cbd8c6 --- /dev/null +++ b/docs/js/components/Import.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Import.js","sourceRoot":"","sources":["../../ts/components/Import.tsx"],"names":[],"mappings":"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","sourcesContent":["import { batch, Signal, useSignal } from '@preact/signals'\nimport { useState } from 'preact/hooks'\nimport { parseEther } from 'ethers'\nimport { connectBrowserProvider, ProviderStore } from '../library/provider.js'\nimport { GetSimulationStackReply } from '../types/interceptorTypes.js'\nimport { Button } from './Button.js'\nimport { AppSettings, Bundle, serialize, Signers } from '../types/types.js'\nimport { EthereumAddress } from '../types/ethereumTypes.js'\nimport { TransactionList } from '../types/bouquetTypes.js'\nimport { ImportModal } from './ImportModal.js'\nimport { SingleNotice } from './Warns.js'\nimport { addressString } from '../library/utils.js'\n\nexport async function importFromInterceptor(\n\tbundle: Signal,\n\tprovider: Signal,\n\tblockInfo: Signal<{\n\t\tblockNumber: bigint\n\t\tbaseFee: bigint\n\t\tpriorityFee: bigint\n\t}>,\n\tappSettings: Signal,\n\tsigners: Signal | undefined,\n) {\n\tif (!window.ethereum || !window.ethereum.request) throw Error('No Ethereum wallet detected')\n\tconnectBrowserProvider(provider, blockInfo, signers, appSettings)\n\n\tconst { payload } = await window.ethereum\n\t\t.request({\n\t\t\tmethod: 'interceptor_getSimulationStack',\n\t\t\tparams: ['1.0.0'],\n\t\t})\n\t\t.catch((err: { code: number }) => {\n\t\t\tif (err?.code === -32601) {\n\t\t\t\tthrow new Error('Wallet does not support returning simulations')\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Unknown Error: ${JSON.stringify(err)}`)\n\t\t\t}\n\t\t})\n\n\tconst tryParse = GetSimulationStackReply.safeParse(payload)\n\tif (!tryParse.success) throw new Error('Wallet does not support returning simulations')\n\tif (tryParse.value.length === 0) throw new Error('You have no transactions on your simulation')\n\n\tconst converted = TransactionList.safeParse(serialize(GetSimulationStackReply, tryParse.value).map(({ from, to, value, input, gasLimit, chainId }) => ({ from, to, value, input, gasLimit, chainId })))\n\tif (!converted.success) throw new Error('Malformed simulation stack')\n\n\tif (converted.value.length >= 2 && converted.value[0].to === converted.value[1].from && converted.value[0].value === parseEther('200000')) {\n\t\tconst fundingAddr = converted.value[0].from\n\t\tconverted.value = converted.value.map(tx => tx.from === fundingAddr ? { ...tx, from: 'FUNDING' } : tx)\n\t}\n\n\tconst uniqueToAddresses = [...new Set(converted.value.map(({ from }) => from))]\n\tconst containsFundingTx = uniqueToAddresses.includes('FUNDING')\n\tconst uniqueSigners = uniqueToAddresses.filter((address): address is EthereumAddress => address !== 'FUNDING').map(address => addressString(address))\n\n\tconst totalGas = converted.value.reduce((sum, tx) => tx.gasLimit + sum, 0n)\n\n\t// Take addresses that recieved funding, determine spend deficit - gas fees\n\tconst fundingRecipients = new Set(converted.value.reduce((result: bigint[], tx) => (tx.to && tx.from === 'FUNDING' ? [...result, tx.to] : result), []))\n\n\tconst spenderDeficits = tryParse.value.reduce((amounts: { [account: string]: { deficit: bigint, credit: bigint } }, tx) => {\n\t\tif (!fundingRecipients.has(tx.from)) return amounts\n\t\tconst receipientBalanceChanges = tx.balanceChanges.filter(x => x.address === tx.from)\n\n\t\tconst consumed = tx.value\n\t\t// Rebate is the difference between balance change and consume amount (if there were any internal transactions sending ETH back), ignore gas fees\n\t\tconst balanceChange = receipientBalanceChanges.reduce((result: bigint, balanceChange) => result + balanceChange.after - balanceChange.before, 0n)\n\t\tconst rebate = balanceChange + consumed + tx.maxPriorityFeePerGas * tx.gasSpent\n\n\t\t// Calcuate current deficit\n\t\tif (tx.from.toString() in amounts) {\n\t\t\t// If credit, deduct current credit from new consumption, or cancel out new consumption and open credit - whichever is smaller\n\t\t\tif (amounts[tx.from.toString()].credit > 0n) {\n\t\t\t\tif (amounts[tx.from.toString()].credit <= consumed) {\n\t\t\t\t\tamounts[tx.from.toString()].deficit += consumed - amounts[tx.from.toString()].credit\n\t\t\t\t\tamounts[tx.from.toString()].credit = rebate\n\t\t\t\t} else {\n\t\t\t\t\t// If consumed less than current rebates, deficit does not increase.\n\t\t\t\t\tamounts[tx.from.toString()].credit += rebate - consumed\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tamounts[tx.from.toString()] = { deficit: consumed, credit: rebate }\n\t\t}\n\t\treturn amounts\n\n\t}, {})\n\n\tconst inputValue = Object.values(spenderDeficits).reduce((sum, spender) => spender.deficit + sum, 0n)\n\n\t// Copy value and set, input of funding to inputValue\n\tconst transactions = [...converted.value]\n\tif (containsFundingTx) {\n\t\ttransactions[0] = { ...transactions[0], value: inputValue }\n\t}\n\n\tlocalStorage.setItem('payload', JSON.stringify(TransactionList.serialize(transactions)))\n\tbundle.value = { transactions, containsFundingTx, uniqueSigners, totalGas, inputValue }\n}\n\nexport const Import = ({\n\tbundle,\n\tprovider,\n\tblockInfo,\n\tsigners,\n\tappSettings,\n}: {\n\tbundle: Signal\n\tprovider: Signal\n\tblockInfo: Signal<{\n\t\tblockNumber: bigint\n\t\tbaseFee: bigint\n\t\tpriorityFee: bigint\n\t}>\n\tsigners: Signal\n\tappSettings: Signal\n}) => {\n\tconst showImportModal = useSignal(false)\n\tconst [error, setError] = useState(undefined)\n\n\tconst clearPayload = () => {\n\t\tbatch(() => {\n\t\t\tbundle.value = undefined\n\t\t\tlocalStorage.removeItem('payload')\n\t\t\tsigners.value.bundleSigners = {}\n\t\t\tsetError('')\n\t\t\t// Keep burner wallet as long as it has funds, should clear is later if there is left over dust but not needed.\n\t\t\t// if (fundingAccountBalance.value === 0n) signers.value.burner = undefined\n\t\t})\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{showImportModal.value ? setError('')} display={showImportModal} /> : null}\n\t\t\t

1. Import

\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t importFromInterceptor(bundle, provider, blockInfo, appSettings, signers).then(() => setError(undefined)).catch((err: Error) => setError(err.message))}\n\t\t\t\t\t>\n\t\t\t\t\t\tImport Payload from The Interceptor\n\t\t\t\t\t\n\t\t\t\t\t showImportModal.value = true}\n\t\t\t\t\t>\n\t\t\t\t\t\tImport From JSON\n\t\t\t\t\t\n\t\t\t\t\t{bundle.value ? (\n\t\t\t\t\t\t\n\t\t\t\t\t) : null}\n\t\t\t\t
\n\t\t\t\t{error ? : null}\n\t\t\t\t{error && error === 'Wallet does not support returning simulations' ? (\n\t\t\t\t\t

\n\t\t\t\t\t\tDon't have The Interceptor Installed? Install it here{' '}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\there\n\t\t\t\t\t\t\n\t\t\t\t\t\t.\n\t\t\t\t\t

\n\t\t\t\t) : (\n\t\t\t\t\t''\n\t\t\t\t)}\n\t\t\t
\n\t\t\n\t)\n\t}\n"]} \ No newline at end of file diff --git a/docs/js/components/ImportModal.d.ts b/docs/js/components/ImportModal.d.ts new file mode 100644 index 0000000..f15840c --- /dev/null +++ b/docs/js/components/ImportModal.d.ts @@ -0,0 +1,9 @@ +import { Signal } from '@preact/signals'; +import { JSX } from 'preact/jsx-runtime'; +import { Bundle } from '../types/types.js'; +export declare const ImportModal: ({ display, bundle, clearError }: { + display: Signal; + clearError: () => void; + bundle: Signal; +}) => JSX.Element | null; +//# sourceMappingURL=ImportModal.d.ts.map \ No newline at end of file diff --git a/docs/js/components/ImportModal.d.ts.map b/docs/js/components/ImportModal.d.ts.map new file mode 100644 index 0000000..d4814b2 --- /dev/null +++ b/docs/js/components/ImportModal.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ImportModal.d.ts","sourceRoot":"","sources":["../../ts/components/ImportModal.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA0B,MAAM,iBAAiB,CAAA;AAChE,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAIxC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAsB1C,eAAO,MAAM,WAAW;aAAgD,OAAO,OAAO,CAAC;gBAAc,MAAM,IAAI;YAAU,OAAO,MAAM,GAAG,SAAS,CAAC;wBAsDlJ,CAAA"} \ No newline at end of file diff --git a/docs/js/components/ImportModal.js b/docs/js/components/ImportModal.js new file mode 100644 index 0000000..47a00cd --- /dev/null +++ b/docs/js/components/ImportModal.js @@ -0,0 +1,57 @@ +import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime"; +import { useComputed, useSignal } from '@preact/signals'; +import { addressString } from '../library/utils.js'; +import { TransactionList } from '../types/bouquetTypes.js'; +import { Button } from './Button.js'; +const placeholder = `[ + { + "from": "0xb3cd36cfaa07652dbfecca76f438ff8998a4f539", + "to": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "value": "0x16345785d8a0000", + "input": "0xd0e30db0", + "chainId": "0x1", + "gasLimit": "0x15f90" + }, + { + "from": "0xb3cd36cfaa07652dbfecca76f438ff8998a4f539", + "to": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "value": "0x0", + "input": "0x2e1a7d4d000000000000000000000000000000000000000000000000016345785d8a0000", + "chainId": "0x1", + "gasLimit": "0x15f90" + } +]`; +export const ImportModal = ({ display, bundle, clearError }) => { + const jsonInput = useSignal(''); + const isValid = useComputed(() => { + if (!jsonInput.value) + return false; + try { + const { success } = TransactionList.safeParse(JSON.parse(jsonInput.value)); + return success; + } + catch { + return false; + } + }); + function importJson() { + if (!isValid.peek()) + return; + const txList = TransactionList.parse(JSON.parse(jsonInput.value)); + localStorage.setItem('payload', JSON.stringify(TransactionList.serialize(txList))); + const uniqueToAddresses = [...new Set(txList.map(({ from }) => from))]; + const containsFundingTx = uniqueToAddresses.includes('FUNDING'); + const uniqueSigners = uniqueToAddresses.filter((address) => address !== 'FUNDING').map(address => addressString(address)); + const totalGas = txList.reduce((sum, tx) => tx.gasLimit + sum, 0n); + const inputValue = txList.reduce((sum, tx) => (tx.from === 'FUNDING' ? tx.value : 0n) + sum, 0n); + bundle.value = { transactions: txList, containsFundingTx, uniqueSigners, totalGas, inputValue }; + clearError(); + close(); + } + function close() { + jsonInput.value = ''; + display.value = false; + } + return display.value ? (_jsx("div", { onClick: close, className: 'bg-white/10 w-full h-full inset-0 fixed p-4 flex flex-col items-center md:pt-24', children: _jsxs("div", { class: 'h-max px-8 py-4 flex flex-col gap-4 bg-black', onClick: (e) => e.stopPropagation(), children: [_jsx("h2", { className: 'text-xl font-semibold', children: "Import Transactions From JSON" }), _jsx("div", { children: _jsx("textarea", { placeholder: placeholder, onInput: (e) => jsonInput.value = e.currentTarget.value, value: jsonInput.value, type: 'url', className: `p-2 w-96 h-96 border ${jsonInput.value && isValid.value ? 'border-green-400 bg-green-200/10' : jsonInput.value && !isValid.value ? 'border-red-400 bg-red-200/10' : 'border-white/50 focus-within:border-white/90 bg-transparent focus-within:bg-white/5'} outline-none px-4` }) }), _jsx("div", { className: 'flex gap-2', children: _jsx(Button, { onClick: importJson, disabled: !isValid.value, variant: 'primary', children: "Import" }) })] }) })) : null; +}; +//# sourceMappingURL=ImportModal.js.map \ No newline at end of file diff --git a/docs/js/components/ImportModal.js.map b/docs/js/components/ImportModal.js.map new file mode 100644 index 0000000..b4ad727 --- /dev/null +++ b/docs/js/components/ImportModal.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ImportModal.js","sourceRoot":"","sources":["../../ts/components/ImportModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Signal, useComputed, useSignal } from '@preact/signals'\nimport { JSX } from 'preact/jsx-runtime'\nimport { addressString } from '../library/utils.js'\nimport { TransactionList } from '../types/bouquetTypes.js'\nimport { EthereumAddress } from '../types/ethereumTypes.js'\nimport { Bundle } from '../types/types.js'\nimport { Button } from './Button.js'\n\nconst placeholder = `[\n {\n \"from\": \"0xb3cd36cfaa07652dbfecca76f438ff8998a4f539\",\n \"to\": \"0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6\",\n \"value\": \"0x16345785d8a0000\",\n \"input\": \"0xd0e30db0\",\n \"chainId\": \"0x1\",\n \"gasLimit\": \"0x15f90\"\n },\n {\n \"from\": \"0xb3cd36cfaa07652dbfecca76f438ff8998a4f539\",\n \"to\": \"0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6\",\n \"value\": \"0x0\",\n \"input\": \"0x2e1a7d4d000000000000000000000000000000000000000000000000016345785d8a0000\",\n \"chainId\": \"0x1\",\n \"gasLimit\": \"0x15f90\"\n }\n]`\n\nexport const ImportModal = ({ display, bundle, clearError }: { display: Signal, clearError: () => void, bundle: Signal }) => {\n\tconst jsonInput = useSignal('')\n\n\tconst isValid = useComputed(() => {\n\t\tif (!jsonInput.value) return false\n\t\ttry {\n\t\t\tconst { success } = TransactionList.safeParse(JSON.parse(jsonInput.value))\n\t\t\treturn success\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t})\n\n\tfunction importJson() {\n\t\tif (!isValid.peek()) return\n\t\tconst txList = TransactionList.parse(JSON.parse(jsonInput.value))\n\n\t\tlocalStorage.setItem('payload', JSON.stringify(TransactionList.serialize(txList)))\n\n\t\tconst uniqueToAddresses = [...new Set(txList.map(({ from }) => from))]\n\t\tconst containsFundingTx = uniqueToAddresses.includes('FUNDING')\n\t\tconst uniqueSigners = uniqueToAddresses.filter((address): address is EthereumAddress => address !== 'FUNDING').map(address => addressString(address))\n\n\t\tconst totalGas = txList.reduce((sum, tx) => tx.gasLimit + sum, 0n)\n\t\tconst inputValue = txList.reduce((sum, tx) => (tx.from === 'FUNDING' ? tx.value : 0n) + sum, 0n)\n\n\t\tbundle.value = { transactions: txList, containsFundingTx, uniqueSigners, totalGas, inputValue }\n\t\tclearError()\n\t\tclose()\n\t}\n\n\tfunction close() {\n\t\tjsonInput.value = ''\n\t\tdisplay.value = false\n\t}\n\treturn display.value ? (\n\t\t
\n\t\t\t
e.stopPropagation()}>\n\t\t\t\t

Import Transactions From JSON

\n\t\t\t\t
\n\t\t\t\t\t) => jsonInput.value = e.currentTarget.value}\n\t\t\t\t\t\tvalue={jsonInput.value}\n\t\t\t\t\t\ttype='url'\n\t\t\t\t\t\tclassName={`p-2 w-96 h-96 border ${jsonInput.value && isValid.value ? 'border-green-400 bg-green-200/10' : jsonInput.value && !isValid.value ? 'border-red-400 bg-red-200/10' : 'border-white/50 focus-within:border-white/90 bg-transparent focus-within:bg-white/5'} outline-none px-4`}\n\t\t\t\t\t/>\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t) : null\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Navbar.d.ts b/docs/js/components/Navbar.d.ts new file mode 100644 index 0000000..382e7ec --- /dev/null +++ b/docs/js/components/Navbar.d.ts @@ -0,0 +1,8 @@ +import { Signal } from '@preact/signals'; +import { ProviderStore } from '../library/provider.js'; +import { AppSettings } from '../types/types.js'; +export declare const Navbar: ({ provider, appSettings }: { + provider: Signal; + appSettings: Signal; +}) => import("preact").JSX.Element; +//# sourceMappingURL=Navbar.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Navbar.d.ts.map b/docs/js/components/Navbar.d.ts.map new file mode 100644 index 0000000..60e76a6 --- /dev/null +++ b/docs/js/components/Navbar.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../ts/components/Navbar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA0B,MAAM,iBAAiB,CAAA;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAEtD,OAAO,EAAE,WAAW,EAAa,MAAM,mBAAmB,CAAA;AAI1D,eAAO,MAAM,MAAM;cAIR,OAAO,aAAa,GAAG,SAAS,CAAC;iBAC9B,OAAO,WAAW,CAAC;kCAuDhC,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Navbar.js b/docs/js/components/Navbar.js new file mode 100644 index 0000000..83d8fca --- /dev/null +++ b/docs/js/components/Navbar.js @@ -0,0 +1,29 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime"; +import { useComputed, useSignal } from '@preact/signals'; +import { NETWORKS } from '../constants.js'; +import { EthereumAddress } from '../types/ethereumTypes.js'; +import { serialize } from '../types/types.js'; +import { Blockie } from './Blockie.js'; +import { SettingsIcon, SettingsModal } from './Settings.js'; +export const Navbar = ({ provider, appSettings }) => { + const switchNetwork = async (e) => { + const elm = e.target; + if (elm.value !== '1' && elm.value !== '5') + return; + const simulationRelayEndpoint = NETWORKS[elm.value].simulationRelay; + const submissionRelayEndpoint = NETWORKS[elm.value].submissionRelay; + if (!provider.value) { + appSettings.value = { ...appSettings.peek(), simulationRelayEndpoint, submissionRelayEndpoint }; + } + else { + provider.peek()?.provider.send('wallet_switchEthereumChain', [{ chainId: simulationRelayEndpoint === NETWORKS['1'].simulationRelay ? '0x1' : '0x5' }]); + } + }; + const blockieScale = useSignal(5); + const showSettings = useSignal(false); + const walletAddress = useComputed(() => provider.value?.walletAddress ?? 0n); + return (_jsxs("div", { className: 'flex flex-col w-full sm:flex-row items-center justify-between gap-4 border-slate-400/30 h-12', children: [_jsx("h1", { className: 'font-extrabold text-4xl', children: "\uD83D\uDC90" }), _jsxs("div", { className: 'flex gap-4 items-center justify-center w-min max-w-full px-4 sm:px-0 text-sm sm:text-md', children: [provider.value ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: 'flex flex-col items-end justify-around h-full w-full', children: [_jsx("p", { className: 'font-bold text-right w-min max-w-full truncate', children: serialize(EthereumAddress, provider.value.walletAddress) }), _jsxs("span", { className: 'text-gray-500 text-md w-max flex gap-1 items-center', children: [_jsx("svg", { width: '1em', height: '1em', viewBox: '0 0 48 48', xmlns: 'http://www.w3.org/2000/svg', className: 'inline-block', children: _jsx("path", { fill: 'currentColor', d: 'M44 32h-2v-8a2 2 0 0 0-2-2H26v-6h2a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-8a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2v6H8a2 2 0 0 0-2 2v8H4a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2h-2v-6h12v6h-2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2h-2v-6h12v6h-2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2Zm-34 8H6v-4h4ZM22 8h4v4h-4Zm4 32h-4v-4h4Zm16 0h-4v-4h4Z', "data-name": 'icons Q2' }) }), _jsxs("select", { value: '1', onChange: switchNetwork, className: 'px-2 py-1 bg-black', children: [_jsx("option", { value: '1', children: "Ethereum" }), _jsx("option", { value: '5', children: "Goerli" }), appSettings.value.simulationRelayEndpoint !== NETWORKS['1'].simulationRelay && appSettings.value.simulationRelayEndpoint !== NETWORKS['5'].simulationRelay ? + _jsx("option", { value: 'custom', children: "Custom" }) + : null] })] })] }), _jsx(Blockie, { address: walletAddress, scale: blockieScale })] })) : (_jsx(_Fragment, { children: _jsx("p", { className: 'w-max', children: "No Wallet Connected" }) })), _jsx("button", { class: 'hover:rotate-45 duration-200 ml-2', onClick: () => (showSettings.value = true), children: _jsx(SettingsIcon, {}) })] }), _jsx(SettingsModal, { display: showSettings, appSettings: appSettings })] })); +}; +//# sourceMappingURL=Navbar.js.map \ No newline at end of file diff --git a/docs/js/components/Navbar.js.map b/docs/js/components/Navbar.js.map new file mode 100644 index 0000000..ebda350 --- /dev/null +++ b/docs/js/components/Navbar.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Navbar.js","sourceRoot":"","sources":["../../ts/components/Navbar.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Signal, useComputed, useSignal } from '@preact/signals'\nimport { NETWORKS } from '../constants.js'\nimport { ProviderStore } from '../library/provider.js'\nimport { EthereumAddress } from '../types/ethereumTypes.js'\nimport { AppSettings, serialize } from '../types/types.js'\nimport { Blockie } from './Blockie.js'\nimport { SettingsIcon, SettingsModal } from './Settings.js'\n\nexport const Navbar = ({\n\tprovider,\n\tappSettings\n}: {\n\tprovider: Signal,\n\tappSettings: Signal\n}) => {\n\tconst switchNetwork = async (e: Event) => {\n\t\tconst elm = e.target as HTMLSelectElement\n\t\tif (elm.value !== '1' && elm.value !== '5') return\n\t\tconst simulationRelayEndpoint = NETWORKS[elm.value].simulationRelay\n\t\tconst submissionRelayEndpoint = NETWORKS[elm.value].submissionRelay\n\t\tif (!provider.value) {\n\t\t\tappSettings.value = { ...appSettings.peek(), simulationRelayEndpoint, submissionRelayEndpoint }\n\t\t} else {\n\t\t\tprovider.peek()?.provider.send('wallet_switchEthereumChain', [{ chainId: simulationRelayEndpoint === NETWORKS['1'].simulationRelay ? '0x1' : '0x5' }])\n\t\t}\n\t}\n\n\tconst blockieScale = useSignal(5)\n\tconst showSettings = useSignal(false)\n\tconst walletAddress = useComputed(() => provider.value?.walletAddress ?? 0n)\n\n\treturn (\n\t\t
\n\t\t\t

💐

\n\t\t\t
\n\t\t\t\t{provider.value ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t

{serialize(EthereumAddress, provider.value.walletAddress)}

\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{appSettings.value.simulationRelayEndpoint !== NETWORKS['1'].simulationRelay && appSettings.value.simulationRelayEndpoint !== NETWORKS['5'].simulationRelay ?\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t

No Wallet Connected

\n\t\t\t\t\t\n\t\t\t\t)}\n\t\t\t\t\n\t\t\t
\n\t\t\t\n\t\t
\n\t)\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Settings.d.ts b/docs/js/components/Settings.d.ts new file mode 100644 index 0000000..be47745 --- /dev/null +++ b/docs/js/components/Settings.d.ts @@ -0,0 +1,9 @@ +import { Signal } from '@preact/signals'; +import { JSX } from 'preact/jsx-runtime'; +import { AppSettings } from '../types/types.js'; +export declare const SettingsIcon: () => JSX.Element; +export declare const SettingsModal: ({ display, appSettings }: { + display: Signal; + appSettings: Signal; +}) => JSX.Element | null; +//# sourceMappingURL=Settings.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Settings.d.ts.map b/docs/js/components/Settings.d.ts.map new file mode 100644 index 0000000..0347f56 --- /dev/null +++ b/docs/js/components/Settings.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../ts/components/Settings.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAA0B,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAG/C,eAAO,MAAM,YAAY,mBAmBxB,CAAA;AAED,eAAO,MAAM,aAAa;aAAyC,OAAO,OAAO,CAAC;iBAAe,OAAO,WAAW,CAAC;wBA2GnH,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Settings.js b/docs/js/components/Settings.js new file mode 100644 index 0000000..3f7130d --- /dev/null +++ b/docs/js/components/Settings.js @@ -0,0 +1,91 @@ +import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime"; +import { batch, useComputed, useSignal } from '@preact/signals'; +import { formatUnits, parseUnits } from 'ethers'; +import { NETWORKS } from '../constants.js'; +import { Button } from './Button.js'; +export const SettingsIcon = () => { + return (_jsxs("svg", { class: 'text-white h-8 w-8', "aria-hidden": 'true', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5, viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', children: [_jsx("path", { d: 'M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z', strokeLinecap: 'round', strokeLinejoin: 'round' }), _jsx("path", { d: 'M15 12a3 3 0 11-6 0 3 3 0 016 0z', strokeLinecap: 'round', strokeLinejoin: 'round' })] })); +}; +export const SettingsModal = ({ display, appSettings }) => { + const simulationRelayEndpointInput = useSignal({ value: appSettings.peek().simulationRelayEndpoint, valid: true }); + const submissionRelayEndpointInput = useSignal({ value: appSettings.peek().submissionRelayEndpoint, valid: true }); + const priorityFeeInput = useSignal({ value: formatUnits(appSettings.peek().priorityFee, 'gwei'), valid: true }); + const blocksInFutureInput = useSignal({ value: appSettings.peek().blocksInFuture.toString(10), valid: true }); + const allValidInputs = useComputed(() => submissionRelayEndpointInput.value.valid && simulationRelayEndpointInput.value.valid && priorityFeeInput.value.valid && blocksInFutureInput.value.valid); + // https://urlregex.com/ + const uriMatcher = new RegExp('^(https?):\\/\\/' + // protocol + '((?:(?:[a-z\\d](?:[a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '(?:(?:\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address + '(?:\\:(\\d+))?' + // port + '((?:\\/[-a-z\\d%_.~+]*)*)' + // path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$' // fragment locator + ); + function validateSimulationRelayEndpointInput(value) { + simulationRelayEndpointInput.value = { value, valid: uriMatcher.test(value) }; + } + function validateAndSetSubmissionRelayEndpointInput(value) { + submissionRelayEndpointInput.value = { value, valid: uriMatcher.test(value) }; + } + function validateAndSetPriorityFeeInput(value) { + if (!value) + return priorityFeeInput.value = { value, valid: false }; + try { + parseUnits(String(Number(value)), 'gwei'); + return priorityFeeInput.value = { value, valid: true }; + } + catch { + return priorityFeeInput.value = { value, valid: false }; + } + } + function validateAndSetBlocksInFutureInput(value) { + if (!value) + return blocksInFutureInput.value = { value, valid: false }; + try { + BigInt(value); + return blocksInFutureInput.value = { value, valid: true }; + } + catch { + return blocksInFutureInput.value = { value, valid: false }; + } + } + function saveSettings() { + if (allValidInputs.value) { + const newSettings = { submissionRelayEndpoint: submissionRelayEndpointInput.value.value, simulationRelayEndpoint: simulationRelayEndpointInput.value.value, priorityFee: parseUnits(String(Number(priorityFeeInput.value.value)), 'gwei'), blocksInFuture: BigInt(blocksInFutureInput.value.value) }; + appSettings.value = newSettings; + localStorage.setItem('bouquetSettings', JSON.stringify({ + priorityFee: newSettings.priorityFee.toString(), + blocksInFuture: newSettings.blocksInFuture.toString(), + simulationRelayEndpoint: newSettings.simulationRelayEndpoint, + submissionRelayEndpoint: newSettings.submissionRelayEndpoint, + })); + close(); + } + } + function resetSettings() { + batch(() => { + appSettings.value = { blocksInFuture: 3n, priorityFee: 10n ** 9n * 3n, simulationRelayEndpoint: NETWORKS['1'].simulationRelay, submissionRelayEndpoint: NETWORKS['1'].submissionRelay }; + localStorage.setItem('bouquetSettings', JSON.stringify({ + priorityFee: appSettings.value.priorityFee.toString(), + blocksInFuture: appSettings.value.blocksInFuture.toString(), + simulationRelayEndpoint: appSettings.value.simulationRelayEndpoint, + submissionRelayEndpoint: appSettings.value.submissionRelayEndpoint, + })); + simulationRelayEndpointInput.value = { value: appSettings.peek().simulationRelayEndpoint, valid: true }; + submissionRelayEndpointInput.value = { value: appSettings.peek().submissionRelayEndpoint, valid: true }; + priorityFeeInput.value = { value: formatUnits(appSettings.peek().priorityFee, 'gwei'), valid: true }; + blocksInFutureInput.value = { value: appSettings.peek().blocksInFuture.toString(10), valid: true }; + }); + } + function close() { + batch(() => { + simulationRelayEndpointInput.value = { value: appSettings.peek().simulationRelayEndpoint, valid: true }; + submissionRelayEndpointInput.value = { value: appSettings.peek().submissionRelayEndpoint, valid: true }; + priorityFeeInput.value = { value: formatUnits(appSettings.peek().priorityFee, 'gwei'), valid: true }; + blocksInFutureInput.value = { value: appSettings.peek().blocksInFuture.toString(10), valid: true }; + display.value = false; + }); + } + return display.value ? (_jsx("div", { onClick: close, className: 'bg-white/10 w-full h-full inset-0 fixed p-4 flex flex-col items-center md:pt-24', children: _jsxs("div", { class: 'h-max px-8 py-4 w-full max-w-xl flex flex-col gap-4 bg-black', onClick: (e) => e.stopPropagation(), children: [_jsx("h2", { className: 'text-xl font-semibold', children: "App Settings" }), _jsxs("div", { className: `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${!simulationRelayEndpointInput.value.valid ? 'border-red-400' : 'border-white/50 focus-within:border-white/80'}`, children: [_jsx("span", { className: 'text-sm text-gray-500', children: "Bundle Simulation Relay URL" }), _jsx("input", { onInput: (e) => validateSimulationRelayEndpointInput(e.currentTarget.value), value: simulationRelayEndpointInput.value.value, type: 'text', className: 'bg-transparent outline-none placeholder:text-gray-600', placeholder: 'https://' })] }), _jsxs("div", { className: `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${!submissionRelayEndpointInput.value.valid ? 'border-red-400' : 'border-white/50 focus-within:border-white/80'}`, children: [_jsx("span", { className: 'text-sm text-gray-500', children: "Bundle Submit Relay URL" }), _jsx("input", { onInput: (e) => validateAndSetSubmissionRelayEndpointInput(e.currentTarget.value), value: submissionRelayEndpointInput.value.value, type: 'text', className: 'bg-transparent outline-none placeholder:text-gray-600', placeholder: 'https://' })] }), _jsxs("div", { className: `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${!priorityFeeInput.value.valid ? 'border-red-400' : 'border-white/50 focus-within:border-white/80'}`, children: [_jsx("span", { className: 'text-sm text-gray-500', children: "Priority Fee (GWEI)" }), _jsx("input", { onInput: (e) => validateAndSetPriorityFeeInput(e.currentTarget.value), value: priorityFeeInput.value.value, type: 'number', className: 'bg-transparent outline-none placeholder:text-gray-600', placeholder: '0.1' })] }), _jsxs("div", { className: `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${!blocksInFutureInput.value.valid ? 'border-red-400' : 'border-white/50 focus-within:border-white/80'}`, children: [_jsx("span", { className: 'text-sm text-gray-500', children: "Target Blocks In Future For Bundle Confirmation" }), _jsx("input", { onInput: (e) => validateAndSetBlocksInFutureInput(e.currentTarget.value), value: blocksInFutureInput.value.value, type: 'number', className: 'bg-transparent outline-none placeholder:text-gray-600' })] }), _jsxs("div", { className: 'flex gap-2', children: [_jsx(Button, { onClick: saveSettings, disabled: !allValidInputs.value, variant: 'primary', children: "Save" }), _jsx(Button, { onClick: resetSettings, variant: 'secondary', children: "Reset" })] })] }) })) : null; +}; +//# sourceMappingURL=Settings.js.map \ No newline at end of file diff --git a/docs/js/components/Settings.js.map b/docs/js/components/Settings.js.map new file mode 100644 index 0000000..9a455d4 --- /dev/null +++ b/docs/js/components/Settings.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Settings.js","sourceRoot":"","sources":["../../ts/components/Settings.tsx"],"names":[],"mappings":"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","sourcesContent":["import { batch, Signal, useComputed, useSignal } from '@preact/signals'\nimport { formatUnits, parseUnits } from 'ethers'\nimport { JSX } from 'preact/jsx-runtime'\nimport { NETWORKS } from '../constants.js'\nimport { AppSettings } from '../types/types.js'\nimport { Button } from './Button.js'\n\nexport const SettingsIcon = () => {\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t)\n}\n\nexport const SettingsModal = ({ display, appSettings }: { display: Signal, appSettings: Signal }) => {\n\tconst simulationRelayEndpointInput = useSignal({ value: appSettings.peek().simulationRelayEndpoint, valid: true })\n\tconst submissionRelayEndpointInput = useSignal({ value: appSettings.peek().submissionRelayEndpoint, valid: true })\n\tconst priorityFeeInput = useSignal({ value: formatUnits(appSettings.peek().priorityFee, 'gwei'), valid: true })\n\tconst blocksInFutureInput = useSignal({ value: appSettings.peek().blocksInFuture.toString(10), valid: true })\n\n\tconst allValidInputs = useComputed(() => submissionRelayEndpointInput.value.valid && simulationRelayEndpointInput.value.valid && priorityFeeInput.value.valid && blocksInFutureInput.value.valid)\n\n\t// https://urlregex.com/\n\tconst uriMatcher = new RegExp(\n\t\t'^(https?):\\\\/\\\\/' + // protocol\n\t\t'((?:(?:[a-z\\\\d](?:[a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|' + // domain name\n\t\t'(?:(?:\\\\d{1,3}\\\\.){3}\\\\d{1,3}))' + // OR IP (v4) address\n\t\t'(?:\\\\:(\\\\d+))?' + // port\n\t\t'((?:\\\\/[-a-z\\\\d%_.~+]*)*)' + // path\n\t\t'(\\\\?[;&a-z\\\\d%_.~+=-]*)?' + // query string\n\t\t'(\\\\#[-a-z\\\\d_]*)?$' // fragment locator\n\t)\n\tfunction validateSimulationRelayEndpointInput(value: string) {\n\t\tsimulationRelayEndpointInput.value = { value, valid: uriMatcher.test(value) }\n\t}\n\tfunction validateAndSetSubmissionRelayEndpointInput(value: string) {\n\t\tsubmissionRelayEndpointInput.value = { value, valid: uriMatcher.test(value) }\n\t}\n\n\tfunction validateAndSetPriorityFeeInput(value: string) {\n\t\tif (!value) return priorityFeeInput.value = { value, valid: false }\n\t\ttry {\n\t\t\tparseUnits(String(Number(value)), 'gwei');\n\t\t\treturn priorityFeeInput.value = { value, valid: true }\n\t\t} catch {\n\t\t\treturn priorityFeeInput.value = { value, valid: false }\n\t\t}\n\t}\n\tfunction validateAndSetBlocksInFutureInput(value: string) {\n\t\tif (!value) return blocksInFutureInput.value = { value, valid: false }\n\t\ttry {\n\t\t\tBigInt(value)\n\t\t\treturn blocksInFutureInput.value = { value, valid: true }\n\t\t} catch {\n\t\t\treturn blocksInFutureInput.value = { value, valid: false }\n\t\t}\n\t}\n\tfunction saveSettings() {\n\t\tif (allValidInputs.value) {\n\t\t\tconst newSettings: AppSettings = { submissionRelayEndpoint: submissionRelayEndpointInput.value.value, simulationRelayEndpoint: simulationRelayEndpointInput.value.value, priorityFee: parseUnits(String(Number(priorityFeeInput.value.value)), 'gwei'), blocksInFuture: BigInt(blocksInFutureInput.value.value) }\n\t\t\tappSettings.value = newSettings\n\t\t\tlocalStorage.setItem('bouquetSettings', JSON.stringify({\n\t\t\t\tpriorityFee: newSettings.priorityFee.toString(),\n\t\t\t\tblocksInFuture: newSettings.blocksInFuture.toString(),\n\t\t\t\tsimulationRelayEndpoint: newSettings.simulationRelayEndpoint,\n\t\t\t\tsubmissionRelayEndpoint: newSettings.submissionRelayEndpoint,\n\t\t\t}))\n\t\t\tclose()\n\t\t}\n\t}\n\tfunction resetSettings() {\n\t\tbatch(() => {\n\t\t\tappSettings.value = { blocksInFuture: 3n, priorityFee: 10n ** 9n * 3n, simulationRelayEndpoint: NETWORKS['1'].simulationRelay, submissionRelayEndpoint: NETWORKS['1'].submissionRelay };\n\t\t\tlocalStorage.setItem('bouquetSettings', JSON.stringify({\n\t\t\t\tpriorityFee: appSettings.value.priorityFee.toString(),\n\t\t\t\tblocksInFuture: appSettings.value.blocksInFuture.toString(),\n\t\t\t\tsimulationRelayEndpoint: appSettings.value.simulationRelayEndpoint,\n\t\t\t\tsubmissionRelayEndpoint: appSettings.value.submissionRelayEndpoint,\n\t\t\t}))\n\t\t\tsimulationRelayEndpointInput.value = { value: appSettings.peek().simulationRelayEndpoint, valid: true }\n\t\t\tsubmissionRelayEndpointInput.value = { value: appSettings.peek().submissionRelayEndpoint, valid: true }\n\t\t\tpriorityFeeInput.value = { value: formatUnits(appSettings.peek().priorityFee, 'gwei'), valid: true }\n\t\t\tblocksInFutureInput.value = { value: appSettings.peek().blocksInFuture.toString(10), valid: true }\n\t\t})\n\t}\n\tfunction close() {\n\t\tbatch(() => {\n\t\t\tsimulationRelayEndpointInput.value = { value: appSettings.peek().simulationRelayEndpoint, valid: true }\n\t\t\tsubmissionRelayEndpointInput.value = { value: appSettings.peek().submissionRelayEndpoint, valid: true }\n\t\t\tpriorityFeeInput.value = { value: formatUnits(appSettings.peek().priorityFee, 'gwei'), valid: true }\n\t\t\tblocksInFutureInput.value = { value: appSettings.peek().blocksInFuture.toString(10), valid: true }\n\t\t\tdisplay.value = false\n\t\t})\n\t}\n\treturn display.value ? (\n\t\t
\n\t\t\t
e.stopPropagation()}>\n\t\t\t\t

App Settings

\n\t\t\t\t
\n\t\t\t\t\tBundle Simulation Relay URL\n\t\t\t\t\t) => validateSimulationRelayEndpointInput(e.currentTarget.value)} value={simulationRelayEndpointInput.value.value} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='https://' />\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tBundle Submit Relay URL\n\t\t\t\t\t) => validateAndSetSubmissionRelayEndpointInput(e.currentTarget.value)} value={submissionRelayEndpointInput.value.value} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='https://' />\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tPriority Fee (GWEI)\n\t\t\t\t\t) => validateAndSetPriorityFeeInput(e.currentTarget.value)} value={priorityFeeInput.value.value} type='number' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='0.1' />\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tTarget Blocks In Future For Bundle Confirmation\n\t\t\t\t\t) => validateAndSetBlocksInFutureInput(e.currentTarget.value)} value={blocksInFutureInput.value.value} type='number' className='bg-transparent outline-none placeholder:text-gray-600' />\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t) : null\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Submit.d.ts b/docs/js/components/Submit.d.ts new file mode 100644 index 0000000..217739b --- /dev/null +++ b/docs/js/components/Submit.d.ts @@ -0,0 +1,50 @@ +import { ReadonlySignal, Signal } from '@preact/signals'; +import { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'; +import { ProviderStore } from '../library/provider.js'; +type PendingBundle = { + bundles: { + [bundleHash: string]: { + targetBlock: bigint; + gas: { + priorityFee: bigint; + baseFee: bigint; + }; + transactions: { + signedTransaction: string; + hash: string; + account: string; + nonce: bigint; + }[]; + included: boolean; + }; + }; + error?: Error; + success?: { + targetBlock: bigint; + gas: { + priorityFee: bigint; + baseFee: bigint; + }; + transactions: { + signedTransaction: string; + hash: string; + account: string; + nonce: bigint; + }[]; + included: boolean; + }; +}; +export declare const Bundles: ({ outstandingBundles, provider }: { + outstandingBundles: Signal; + provider: Signal; +}) => import("preact").JSX.Element; +export declare const Submit: ({ provider, bundle, fundingAmountMin, signers, appSettings, blockInfo, }: { + provider: Signal; + bundle: Signal; + signers: Signal; + fundingAmountMin: ReadonlySignal; + appSettings: Signal; + blockInfo: Signal; +}) => import("preact").JSX.Element; +export {}; +//# sourceMappingURL=Submit.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Submit.d.ts.map b/docs/js/components/Submit.d.ts.map new file mode 100644 index 0000000..36ee44f --- /dev/null +++ b/docs/js/components/Submit.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Submit.d.ts","sourceRoot":"","sources":["../../ts/components/Submit.tsx"],"names":[],"mappings":"AACA,OAAO,EAAS,cAAc,EAAE,MAAM,EAA2C,MAAM,iBAAiB,CAAA;AAGxG,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAOtD,KAAK,aAAa,GAAG;IACpB,OAAO,EAAE;QACR,CAAC,UAAU,EAAE,MAAM,GAAG;YACrB,WAAW,EAAE,MAAM,CAAC;YACpB,GAAG,EAAE;gBAAE,WAAW,EAAE,MAAM,CAAC;gBAAC,OAAO,EAAE,MAAM,CAAA;aAAE,CAAA;YAC7C,YAAY,EAAE;gBAAE,iBAAiB,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAC;gBAAC,OAAO,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,EAAE,CAAA;YAC3F,QAAQ,EAAE,OAAO,CAAA;SACjB,CAAA;KACD,CAAA;IACD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,GAAG,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;QAC7C,YAAY,EAAE;YAAE,iBAAiB,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QAC3F,QAAQ,EAAE,OAAO,CAAA;KACjB,CAAA;CACD,CAAA;AA6CD,eAAO,MAAM,OAAO;wBAIC,OAAO,aAAa,CAAC;cAC/B,OAAO,aAAa,GAAG,SAAS,CAAC;kCA6B3C,CAAA;AAED,eAAO,MAAM,MAAM;cAQR,OAAO,aAAa,GAAG,SAAS,CAAC;YACnC,OAAO,MAAM,GAAG,SAAS,CAAC;aACzB,OAAO,OAAO,CAAC;sBACN,eAAe,MAAM,CAAC;iBAC3B,OAAO,WAAW,CAAC;eACrB,OAAO,SAAS,CAAC;kCAmK5B,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Submit.js b/docs/js/components/Submit.js new file mode 100644 index 0000000..f2ea400 --- /dev/null +++ b/docs/js/components/Submit.js @@ -0,0 +1,145 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime"; +import { EtherSymbol, formatEther, formatUnits } from 'ethers'; +import { batch, useComputed, useSignal, useSignalEffect } from '@preact/signals'; +import { getMaxBaseFeeInFutureBlock } from '../library/bundleUtils.js'; +import { Button } from './Button.js'; +import { SettingsModal } from './Settings.js'; +import { useAsyncState } from '../library/asyncState.js'; +import { simulateBundle, sendBundle, checkBundleInclusion } from '../library/flashbots.js'; +import { SingleNotice } from './Warns.js'; +import { NETWORKS } from '../constants.js'; +const SimulationResult = ({ state }) => { + if (state.value.state === 'pending') + return _jsx("div", { children: "Simulating..." }); + if (state.value.state === 'resolved') { + return state.value.value.firstRevert ? + _jsx(SingleNotice, { variant: 'error', title: 'A Transaction Reverted During Simulation', description: _jsxs("div", { class: 'flex w-full min-h-[96px] border border-white/90 mt-4', children: [_jsx("div", { class: 'flex w-16 flex-col items-center justify-center text-white', children: _jsxs("span", { class: 'text-lg font-bold', children: ["#", state.value.value.results.findIndex((x) => 'error' in x)] }) }), _jsxs("div", { class: 'bg-gray-500/30 flex w-full justify-center flex-col gap-2 p-4 text-sm font-semibold', children: [_jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-16 text-right', children: "From" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: state.value.value.firstRevert.fromAddress })] }), _jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-16 text-right', children: "To" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: state.value.value.firstRevert.toAddress })] }), _jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-16 text-right', children: "Gas Used" }), _jsxs("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: [state.value.value.firstRevert.gasUsed, " gas"] })] }), _jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-16 text-right', children: "Error" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: 'error' in state.value.value.firstRevert ? String(state.value.value.firstRevert.error) : 'Unknown' })] })] })] }) }) + : _jsx(SingleNotice, { variant: 'success', title: 'Simulation Succeeded', description: _jsxs("p", { children: [_jsx("b", { children: state.value.value.results.length }), " Transactions succeeded, consuming ", _jsx("b", { children: state.value.value.totalGasUsed }), " gas with a total fee of ", _jsxs("b", { children: [EtherSymbol, formatEther(state.value.value.gasFees)] }), "."] }) }); + } + if (state.value.state === 'rejected') { + return _jsx(SingleNotice, { variant: 'error', title: 'Simulation Failed', description: _jsx("p", { class: 'font-medium w-full break-all', children: state.value.error.message }) }); + } + return _jsx(_Fragment, {}); +}; +export const Bundles = ({ outstandingBundles, provider }) => { + if (outstandingBundles.value.error) + return _jsx(SingleNotice, { variant: 'error', title: 'Error Sending Bundle', description: _jsx("p", { class: 'font-medium w-full break-all', children: outstandingBundles.value.error.message }) }); + const chainIdString = provider.value ? provider.value.chainId.toString(10) : '-1'; + const blockExplorerBaseUrl = NETWORKS[chainIdString].blockExplorer ?? null; + return (_jsx("div", { class: 'flex flex-col-reverse gap-4', children: outstandingBundles.value.success + ? _jsx(SingleNotice, { variant: 'success', title: 'Bundle Included!', description: _jsxs("div", { children: [_jsxs("h3", { class: 'text-md', children: [_jsx("b", { children: outstandingBundles.value.success.transactions.length }), " transactions were included in block ", _jsx("b", { children: outstandingBundles.value.success.targetBlock.toString(10) })] }), _jsx("div", { class: 'flex flex-col gap-1 py-1', children: outstandingBundles.value.success.transactions.map((tx, index) => blockExplorerBaseUrl + ? _jsxs("p", { class: 'flex items-center gap-2', children: [_jsxs("b", { children: ["#", index] }), _jsxs("a", { class: 'underline text-white/50 flex items-center gap-2', href: `${blockExplorerBaseUrl}tx/${tx.hash}`, target: "_blank", children: [tx.hash, _jsxs("svg", { "aria-hidden": "true", class: 'h-6', fill: "none", stroke: "currentColor", "stroke-width": "1.5", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: [" ", _jsx("path", { d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25", "stroke-linecap": "round", "stroke-linejoin": "round" })] })] })] }) + : _jsxs("p", { children: [_jsxs("b", { children: ["#", index] }), " ", _jsx("span", { class: 'semibold text-white/50', children: tx.hash })] })) })] }) }) + : Object.values(outstandingBundles.value.bundles).map((bundle) => _jsxs("div", { class: 'flex items-center gap-2 text-white', children: [_jsxs("svg", { class: 'animate-spin h-4 w-4 text-white', xmlns: 'http://www.w3.org/2000/svg', fill: 'none', viewBox: '0 0 24 24', children: [_jsx("circle", { class: 'opacity-25', cx: '12', cy: '12', r: '10', stroke: 'currentColor', "stroke-width": '4' }), _jsx("path", { class: 'opacity-75', fill: 'currentColor', d: 'M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z' })] }), _jsxs("p", { children: ["Attempting to get bundle included before block ", bundle.targetBlock.toString(10), " with max fee of ", Number(formatUnits(bundle.gas.baseFee + bundle.gas.priorityFee, 'gwei')).toPrecision(3), " gwei per gas"] })] })) })); +}; +export const Submit = ({ provider, bundle, fundingAmountMin, signers, appSettings, blockInfo, }) => { + // General component state + const showSettings = useSignal(false); + const missingRequirements = useComputed(() => { + if (!bundle.value) + return 'No transactions imported yet.'; + const missingSigners = bundle.value.uniqueSigners.length !== Object.keys(signers.value.bundleSigners).length; + const insufficientBalance = signers.value.burnerBalance < fundingAmountMin.value; + if (missingSigners && insufficientBalance) + return 'Missing private keys for signing accounts and funding wallet has insufficent balance.'; + if (missingSigners) + return 'Missing private keys for signing accounts.'; + if (insufficientBalance) + return 'Funding wallet has insufficent balance.'; + return false; + }); + // Simulations + const { value: simulationPromise, waitFor: waitForSimulation } = useAsyncState(); + async function simulateCallback() { + if (!provider.value) + throw 'User not connected'; + if (!bundle.value) + throw 'No imported bundle found'; + const simulationResult = await simulateBundle(bundle.value, fundingAmountMin.peek(), provider.value, signers.peek(), blockInfo.peek(), appSettings.peek()); + if ('error' in simulationResult) + throw new Error(simulationResult.error.message); + else + return simulationResult; + } + // Submissions + const submissionStatus = useSignal({ active: false, lastBlock: 0n }); + const outstandingBundles = useSignal({ bundles: {} }); + useSignalEffect(() => { + if (blockInfo.value.blockNumber > submissionStatus.value.lastBlock) { + bundleSubmission(blockInfo.value.blockNumber); + } + }); + async function bundleSubmission(blockNumber) { + submissionStatus.value = { ...submissionStatus.peek(), lastBlock: blockNumber }; + if (!provider.value) + throw new Error('User not connected'); + if (!bundle.value) + throw new Error('No imported bundle found'); + const providerStore = provider.value; + // Check status of current bundles + const checkedPending = await Promise.all(Object.keys(outstandingBundles.peek().bundles).map(bundleHash => checkBundleInclusion(outstandingBundles.peek().bundles[bundleHash].transactions, providerStore))); + const included = checkedPending.filter(checkedPending => checkedPending.included); + if (included.length > 0) { + // We done! + batch(() => { + const checkedBundles = Object.keys(outstandingBundles.peek().bundles).reduce((checked, current, index) => { + if (checkedPending[index].included) { + checked[current] = outstandingBundles.peek().bundles[current]; + checked[current].included = checkedPending[index].included; + } + return checked; + }, {}); + outstandingBundles.value = { + error: outstandingBundles.peek().error, + bundles: checkedBundles, + success: Object.values(checkedBundles).find(x => x.included) + }; + submissionStatus.value = { active: false, lastBlock: blockNumber }; + simulationPromise.value = { ...simulationPromise.value, state: 'inactive' }; + }); + } + else { + // Remove old submissions + outstandingBundles.value = { + error: outstandingBundles.peek().error, + success: outstandingBundles.peek().success, + bundles: Object.keys(outstandingBundles.peek().bundles) + .filter(tx => outstandingBundles.peek().bundles[tx].targetBlock + 1n > blockNumber) + .reduce((obj, bundleHash) => { + obj[bundleHash] = outstandingBundles.peek().bundles[bundleHash]; + return obj; + }, {}) + }; + // Try Submit + if (submissionStatus.value.active && !outstandingBundles.value.success) { + try { + const targetBlock = blockNumber + appSettings.peek().blocksInFuture; + const gas = blockInfo.peek(); + gas.priorityFee = appSettings.value.priorityFee; + const bundleRequest = await sendBundle(bundle.value, targetBlock, fundingAmountMin.peek(), provider.value, signers.peek(), blockInfo.peek(), appSettings.peek()); + if (!(bundleRequest.bundleHash in outstandingBundles.peek().bundles)) { + outstandingBundles.value = { ...outstandingBundles.peek(), bundles: { ...outstandingBundles.peek().bundles, [bundleRequest.bundleHash]: { targetBlock, gas, transactions: bundleRequest.bundleTransactions, included: false } } }; + } + } + catch (err) { + console.error('SendBundle error', err); + const error = err && typeof err === 'object' && 'message' in err && typeof err.message === 'string' ? new Error(err.message) : new Error('Unknown Error'); + batch(() => { + submissionStatus.value = { active: false, lastBlock: blockNumber }; + outstandingBundles.value = { ...outstandingBundles.peek(), error }; + }); + } + } + } + } + async function toggleSubmission() { + batch(() => { + simulationPromise.value = { ...simulationPromise.value, state: 'inactive' }; + outstandingBundles.value = { bundles: !outstandingBundles.peek().success ? outstandingBundles.peek().bundles : {}, error: undefined, success: submissionStatus.peek().active ? outstandingBundles.peek().success : undefined }; + submissionStatus.value = { ...submissionStatus.peek(), active: !submissionStatus.peek().active }; + }); + bundleSubmission(blockInfo.peek().blockNumber); + } + return (_jsxs(_Fragment, { children: [_jsxs("h2", { className: 'font-bold text-2xl', children: [_jsx("span", { class: 'text-gray-500', children: "3." }), " Submit"] }), _jsx(SettingsModal, { display: showSettings, appSettings: appSettings }), !outstandingBundles.value.success && missingRequirements.value ? (_jsx("p", { children: missingRequirements.peek() })) : (_jsxs("div", { className: 'flex flex-col w-full gap-4', children: [_jsxs("div", { children: [_jsxs("p", { children: [_jsx("span", { className: 'font-bold', children: "Gas:" }), " ", formatUnits(getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, appSettings.value.blocksInFuture), 'gwei'), " gwei + ", formatUnits(appSettings.value.priorityFee.toString(), 'gwei'), " gwei priority"] }), _jsxs("p", { children: [_jsx("span", { className: 'font-bold', children: "Relays:" }), " simulation:", appSettings.value.simulationRelayEndpoint, ", submit:", appSettings.value.submissionRelayEndpoint, " (Block ", blockInfo.value.blockNumber.toString(), ")"] }), _jsxs("p", { children: ["Transactions will be attempt to be included in the block ", appSettings.value.blocksInFuture.toString(), " blocks from now."] }), _jsxs("p", { children: ["You can edit these settings ", _jsx("button", { className: 'font-bold underline', onClick: () => showSettings.value = true, children: "here" }), "."] })] }), _jsxs("div", { className: 'flex flex-row gap-6', children: [_jsx(Button, { onClick: () => waitForSimulation(simulateCallback), disabled: simulationPromise.value.state === 'pending', variant: 'secondary', children: "Simulate" }), _jsx(Button, { onClick: toggleSubmission, children: submissionStatus.value.active ? 'Stop Submitting Bundle' : 'Submit' })] }), _jsx(SimulationResult, { state: simulationPromise }), _jsx(Bundles, { outstandingBundles: outstandingBundles, provider: provider })] }))] })); +}; +//# sourceMappingURL=Submit.js.map \ No newline at end of file diff --git a/docs/js/components/Submit.js.map b/docs/js/components/Submit.js.map new file mode 100644 index 0000000..28d07d6 --- /dev/null +++ b/docs/js/components/Submit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Submit.js","sourceRoot":"","sources":["../../ts/components/Submit.tsx"],"names":[],"mappings":"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","sourcesContent":["import { EtherSymbol, formatEther, formatUnits } from 'ethers'\nimport { batch, ReadonlySignal, Signal, useComputed, useSignal, useSignalEffect } from '@preact/signals'\nimport { getMaxBaseFeeInFutureBlock } from '../library/bundleUtils.js'\nimport { Button } from './Button.js'\nimport { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'\nimport { ProviderStore } from '../library/provider.js'\nimport { SettingsModal } from './Settings.js'\nimport { useAsyncState, AsyncProperty } from '../library/asyncState.js'\nimport { simulateBundle, sendBundle, checkBundleInclusion, RelayResponseError, SimulationResponseSuccess } from '../library/flashbots.js'\nimport { SingleNotice } from './Warns.js'\nimport { NETWORKS } from '../constants.js'\n\ntype PendingBundle = {\n\tbundles: {\n\t\t[bundleHash: string]: {\n\t\t\ttargetBlock: bigint,\n\t\t\tgas: { priorityFee: bigint, baseFee: bigint }\n\t\t\ttransactions: { signedTransaction: string, hash: string, account: string, nonce: bigint }[]\n\t\t\tincluded: boolean\n\t\t}\n\t}\n\terror?: Error,\n\tsuccess?: {\n\t\ttargetBlock: bigint,\n\t\tgas: { priorityFee: bigint, baseFee: bigint }\n\t\ttransactions: { signedTransaction: string, hash: string, account: string, nonce: bigint }[]\n\t\tincluded: boolean\n\t}\n}\n\nconst SimulationResult = ({\n\tstate\n}: {\n\tstate: Signal>\n}) => {\n\tif (state.value.state === 'pending') return
Simulating...
\n\tif (state.value.state === 'resolved') {\n\t\treturn state.value.value.firstRevert ?\n\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t#{state.value.value.results.findIndex((x) => 'error' in x)}\n\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\tFrom\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{state.value.value.firstRevert.fromAddress}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\tTo\n\t\t\t\t\t\t\t{state.value.value.firstRevert.toAddress}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\tGas Used\n\t\t\t\t\t\t\t{state.value.value.firstRevert.gasUsed} gas\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\tError\n\t\t\t\t\t\t\t{'error' in state.value.value.firstRevert ? String(state.value.value.firstRevert.error) : 'Unknown'}\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\n\t\t\t} />\n\t\t\t: {state.value.value.results.length} Transactions succeeded, consuming {state.value.value.totalGasUsed} gas with a total fee of {EtherSymbol}{formatEther(state.value.value.gasFees)}.

} />\n\t}\n\tif (state.value.state === 'rejected') {\n\t\treturn {state.value.error.message}

} />\n\t}\n\treturn <>\n}\n\nexport const Bundles = ({\n\toutstandingBundles,\n\tprovider\n}: {\n\toutstandingBundles: Signal,\n\tprovider: Signal\n}) => {\n\tif (outstandingBundles.value.error) return {outstandingBundles.value.error.message}

} />\n\n\tconst chainIdString = provider.value ? provider.value.chainId.toString(10) : '-1'\n\tconst blockExplorerBaseUrl = NETWORKS[chainIdString].blockExplorer ?? null\n\n\treturn (\n\t\t
\n\t\t\t{outstandingBundles.value.success\n\t\t\t\t? \n\t\t\t\t\t\t

{outstandingBundles.value.success.transactions.length} transactions were included in block {outstandingBundles.value.success.targetBlock.toString(10)}

\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{outstandingBundles.value.success.transactions.map((tx, index) => blockExplorerBaseUrl\n\t\t\t\t\t\t\t\t?

#{index}{tx.hash}

\n\t\t\t\t\t\t\t\t:

#{index} {tx.hash}

\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t
\n\t\t\t\t\t
} />\n\t\t\t\t: Object.values(outstandingBundles.value.bundles).map((bundle) =>
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t

Attempting to get bundle included before block {bundle.targetBlock.toString(10)} with max fee of {Number(formatUnits(bundle.gas.baseFee + bundle.gas.priorityFee, 'gwei')).toPrecision(3)} gwei per gas

\n\t\t\t\t\t
\n\t\t\t)}\n\t\t\n\t)\n}\n\nexport const Submit = ({\n\tprovider,\n\tbundle,\n\tfundingAmountMin,\n\tsigners,\n\tappSettings,\n\tblockInfo,\n}: {\n\tprovider: Signal\n\tbundle: Signal\n\tsigners: Signal\n\tfundingAmountMin: ReadonlySignal\n\tappSettings: Signal\n\tblockInfo: Signal\n}) => {\n\t// General component state\n\tconst showSettings = useSignal(false)\n\n\tconst missingRequirements = useComputed(() => {\n\t\tif (!bundle.value) return 'No transactions imported yet.'\n\t\tconst missingSigners = bundle.value.uniqueSigners.length !== Object.keys(signers.value.bundleSigners).length\n\t\tconst insufficientBalance = signers.value.burnerBalance < fundingAmountMin.value\n\t\tif (missingSigners && insufficientBalance) return 'Missing private keys for signing accounts and funding wallet has insufficent balance.'\n\t\tif (missingSigners) return 'Missing private keys for signing accounts.'\n\t\tif (insufficientBalance) return 'Funding wallet has insufficent balance.'\n\t\treturn false\n\t})\n\n\t// Simulations\n\tconst { value: simulationPromise, waitFor: waitForSimulation } = useAsyncState()\n\n\tasync function simulateCallback() {\n\t\tif (!provider.value) throw 'User not connected'\n\t\tif (!bundle.value) throw 'No imported bundle found'\n\t\tconst simulationResult = await simulateBundle(\n\t\t\tbundle.value,\n\t\t\tfundingAmountMin.peek(),\n\t\t\tprovider.value,\n\t\t\tsigners.peek(),\n\t\t\tblockInfo.peek(),\n\t\t\tappSettings.peek()\n\t\t)\n\t\tif ('error' in simulationResult) throw new Error((simulationResult as RelayResponseError).error.message)\n\t\telse return simulationResult\n\t}\n\n\t// Submissions\n\tconst submissionStatus = useSignal<{ active: boolean, lastBlock: bigint }>({ active: false, lastBlock: 0n })\n\tconst outstandingBundles = useSignal({ bundles: {} })\n\n\tuseSignalEffect(() => {\n\t\tif (blockInfo.value.blockNumber > submissionStatus.value.lastBlock) {\n\t\t\tbundleSubmission(blockInfo.value.blockNumber)\n\t\t}\n\t})\n\n\tasync function bundleSubmission(blockNumber: bigint) {\n\t\tsubmissionStatus.value = { ...submissionStatus.peek(), lastBlock: blockNumber }\n\n\t\tif (!provider.value) throw new Error('User not connected')\n\t\tif (!bundle.value) throw new Error('No imported bundle found')\n\t\tconst providerStore = provider.value\n\n\t\t// Check status of current bundles\n\t\tconst checkedPending = await Promise.all(Object.keys(outstandingBundles.peek().bundles).map(bundleHash => checkBundleInclusion(outstandingBundles.peek().bundles[bundleHash].transactions, providerStore)))\n\t\tconst included = checkedPending.filter(checkedPending => checkedPending.included)\n\t\tif (included.length > 0) {\n\t\t\t// We done!\n\t\t\tbatch(() => {\n\t\t\t\tconst checkedBundles = Object.keys(outstandingBundles.peek().bundles).reduce((checked: {\n\t\t\t\t\t[bundleHash: string]: {\n\t\t\t\t\t\ttargetBlock: bigint,\n\t\t\t\t\t\tgas: { priorityFee: bigint, baseFee: bigint }\n\t\t\t\t\t\ttransactions: { signedTransaction: string, hash: string, account: string, nonce: bigint }[]\n\t\t\t\t\t\tincluded: boolean\n\t\t\t\t\t}\n\t\t\t\t}, current, index) => {\n\t\t\t\t\tif (checkedPending[index].included) {\n\t\t\t\t\t\tchecked[current] = outstandingBundles.peek().bundles[current]\n\t\t\t\t\t\tchecked[current].included = checkedPending[index].included\n\t\t\t\t\t}\n\t\t\t\t\treturn checked\n\t\t\t\t}, {})\n\t\t\t\toutstandingBundles.value = {\n\t\t\t\t\terror: outstandingBundles.peek().error,\n\t\t\t\t\tbundles: checkedBundles,\n\t\t\t\t\tsuccess: Object.values(checkedBundles).find(x => x.included)\n\t\t\t\t}\n\t\t\t\tsubmissionStatus.value = { active: false, lastBlock: blockNumber }\n\t\t\t\tsimulationPromise.value = { ...simulationPromise.value, state: 'inactive' }\n\t\t\t})\n\t\t} else {\n\t\t\t// Remove old submissions\n\t\t\toutstandingBundles.value = {\n\t\t\t\terror: outstandingBundles.peek().error,\n\t\t\t\tsuccess: outstandingBundles.peek().success,\n\t\t\t\tbundles: Object.keys(outstandingBundles.peek().bundles)\n\t\t\t\t\t.filter(tx => outstandingBundles.peek().bundles[tx].targetBlock + 1n > blockNumber)\n\t\t\t\t\t.reduce((obj: {\n\t\t\t\t\t\t[bundleHash: string]: {\n\t\t\t\t\t\t\ttargetBlock: bigint,\n\t\t\t\t\t\t\tgas: { priorityFee: bigint, baseFee: bigint }\n\t\t\t\t\t\t\ttransactions: { signedTransaction: string, hash: string, account: string, nonce: bigint }[]\n\t\t\t\t\t\t\tincluded: boolean\n\t\t\t\t\t\t}\n\t\t\t\t\t}, bundleHash) => {\n\t\t\t\t\t\tobj[bundleHash] = outstandingBundles.peek().bundles[bundleHash]\n\t\t\t\t\t\treturn obj\n\t\t\t\t\t}, {})\n\t\t\t}\n\n\t\t\t// Try Submit\n\t\t\tif (submissionStatus.value.active && !outstandingBundles.value.success) {\n\t\t\t\ttry {\n\t\t\t\t\tconst targetBlock = blockNumber + appSettings.peek().blocksInFuture\n\t\t\t\t\tconst gas = blockInfo.peek()\n\t\t\t\t\tgas.priorityFee = appSettings.value.priorityFee\n\n\t\t\t\t\tconst bundleRequest = await sendBundle(\n\t\t\t\t\t\tbundle.value,\n\t\t\t\t\t\ttargetBlock,\n\t\t\t\t\t\tfundingAmountMin.peek(),\n\t\t\t\t\t\tprovider.value,\n\t\t\t\t\t\tsigners.peek(),\n\t\t\t\t\t\tblockInfo.peek(),\n\t\t\t\t\t\tappSettings.peek()\n\t\t\t\t\t)\n\n\t\t\t\t\tif (!(bundleRequest.bundleHash in outstandingBundles.peek().bundles)) {\n\t\t\t\t\t\toutstandingBundles.value = { ...outstandingBundles.peek(), bundles: {...outstandingBundles.peek().bundles, [bundleRequest.bundleHash]: { targetBlock, gas, transactions: bundleRequest.bundleTransactions, included: false } } }\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error('SendBundle error', err)\n\t\t\t\t\tconst error = err && typeof err === 'object' && 'message' in err && typeof err.message === 'string' ? new Error(err.message) : new Error('Unknown Error')\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tsubmissionStatus.value = { active: false, lastBlock: blockNumber }\n\t\t\t\t\t\toutstandingBundles.value = { ...outstandingBundles.peek(), error }\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function toggleSubmission() {\n\t\tbatch(() => {\n\t\t\tsimulationPromise.value = { ...simulationPromise.value, state: 'inactive' }\n\t\t\toutstandingBundles.value = { bundles: !outstandingBundles.peek().success ? outstandingBundles.peek().bundles : {}, error: undefined, success: submissionStatus.peek().active ? outstandingBundles.peek().success : undefined }\n\t\t\tsubmissionStatus.value = { ...submissionStatus.peek(), active: !submissionStatus.peek().active }\n\t\t})\n\t\tbundleSubmission(blockInfo.peek().blockNumber)\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t

3. Submit

\n\t\t\t\n\t\t\t{!outstandingBundles.value.success && missingRequirements.value ? (\n\t\t\t\t

{missingRequirements.peek()}

\n\t\t\t) : (\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t

Gas: {formatUnits(getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, appSettings.value.blocksInFuture), 'gwei')} gwei + {formatUnits(appSettings.value.priorityFee.toString(), 'gwei')} gwei priority

\n\t\t\t\t\t\t

Relays: simulation:{appSettings.value.simulationRelayEndpoint}, submit:{appSettings.value.submissionRelayEndpoint} (Block {blockInfo.value.blockNumber.toString()})

\n\t\t\t\t\t\t

Transactions will be attempt to be included in the block {appSettings.value.blocksInFuture.toString()} blocks from now.

\n\t\t\t\t\t\t

You can edit these settings .

\n\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t)}\n\t\t\n\t)\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Transactions.d.ts b/docs/js/components/Transactions.d.ts new file mode 100644 index 0000000..969c962 --- /dev/null +++ b/docs/js/components/Transactions.d.ts @@ -0,0 +1,13 @@ +import { ReadonlySignal, Signal } from '@preact/signals'; +import { JSXInternal } from 'preact/src/jsx.js'; +import { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'; +import { ProviderStore } from '../library/provider.js'; +export declare const Transactions: ({ provider, bundle, blockInfo, appSettings, signers }: { + provider: Signal; + bundle: Signal; + blockInfo: Signal; + signers: Signal; + appSettings: Signal; + fundingAmountMin: ReadonlySignal; +}) => JSXInternal.Element; +//# sourceMappingURL=Transactions.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Transactions.d.ts.map b/docs/js/components/Transactions.d.ts.map new file mode 100644 index 0000000..4dea4ab --- /dev/null +++ b/docs/js/components/Transactions.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Transactions.d.ts","sourceRoot":"","sources":["../../ts/components/Transactions.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,EAA8B,MAAM,iBAAiB,CAAA;AAEpF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAa,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAsBtD,eAAO,MAAM,YAAY;cAOd,OAAO,aAAa,GAAG,SAAS,CAAC;YACnC,OAAO,MAAM,GAAG,SAAS,CAAC;eACvB,OAAO,SAAS,CAAC;aACnB,OAAO,OAAO,CAAC;iBACX,OAAO,WAAW,CAAC;sBACd,eAAe,MAAM,CAAC;yBA4KxC,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Transactions.js b/docs/js/components/Transactions.js new file mode 100644 index 0000000..2e9b69f --- /dev/null +++ b/docs/js/components/Transactions.js @@ -0,0 +1,125 @@ +import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime"; +import { useSignal, useSignalEffect } from '@preact/signals'; +import { EtherSymbol, formatEther, getAddress, Interface, parseEther } from 'ethers'; +import { serialize } from '../types/types.js'; +import { NETWORKS } from '../constants.js'; +import { Button } from './Button.js'; +import { useAsyncState } from '../library/asyncState.js'; +import { TransactionList } from '../types/bouquetTypes.js'; +import { SingleNotice } from './Warns.js'; +import { GetSimulationStackReply } from '../types/interceptorTypes.js'; +import { addressString } from '../library/utils.js'; +import { importFromInterceptor } from './Import.js'; +import { EtherscanGetABIResult, EtherscanSourceCodeResult } from '../types/apiTypes.js'; +function formatTransactionDescription(tx) { + if (tx.fragment.inputs.length === 0) + return _jsx(_Fragment, { children: `${tx.name}()` }); + const params = tx.fragment.inputs.map((y, index) => _jsx("p", { class: 'pl-4', children: `${y.name}: ${tx.args[index].toString()}` })); + return (_jsxs(_Fragment, { children: [_jsx("p", { children: `${tx.name}(` }), params, _jsx("p", { children: ")" })] })); +} +export const Transactions = ({ provider, bundle, blockInfo, appSettings, signers }) => { + const interfaces = useSignal({}); + const decodedTransactions = useSignal([]); + const interceptorComparison = useSignal({ different: true }); + function copyTransactions() { + if (!bundle.value) + return; + const parsedList = TransactionList.safeSerialize(bundle.value.transactions); + if ('success' in parsedList && parsedList.success) + navigator.clipboard.writeText(JSON.stringify(parsedList.value, null, 2)); + } + const fetchingAbis = useAsyncState(); + async function fetchAbis() { + if (!bundle.value || !bundle.value.transactions) + return; + try { + const uniqueAddresses = [...new Set(bundle.value.transactions.map((tx) => tx.to ? addressString(tx.to) : null).filter(addr => addr))]; + const abis = []; + const requests = await Promise.all(uniqueAddresses.map((address) => fetch(`https://api${appSettings.peek().simulationRelayEndpoint === NETWORKS['5'].simulationRelay ? '-goerli' : ''}.etherscan.io/api?module=contract&action=getsourcecode&address=${getAddress(address.toLowerCase())}&apiKey=PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8`))); + const sourcecodeResults = await Promise.all(requests.map((request) => request.json())); + const parsedSourceCode = sourcecodeResults.map(x => EtherscanSourceCodeResult.safeParse(x)); + // Extract ABI from getSourceCode request if not proxy, otherwise attempt to fetch ABI of implementation + for (const contract of parsedSourceCode) { + if (contract.success == false || contract.value.status !== '1') + abis.push(undefined); + else { + if (contract.value.result[0].Proxy === '1' && contract.value.result[0].Implementation !== '') { + const implReq = await fetch(`https://api${appSettings.peek().simulationRelayEndpoint === NETWORKS['5'].simulationRelay ? '-goerli' : ''}.etherscan.io/api?module=contract&action=getabi&address=${addressString(contract.value.result[0].Implementation)}&apiKey=PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8`); + const implResult = EtherscanGetABIResult.safeParse(await implReq.json()); + abis.push(implResult.success && implResult.value.status === '1' ? implResult.value.result : undefined); + } + else + abis.push(contract.value.result[0].ABI && contract.value.result[0].ABI !== 'Contract source code not verified' ? contract.value.result[0].ABI : undefined); + } + } + interfaces.value = abis.reduce((acc, curr, index) => { + if (curr) + return { ...acc, [`${uniqueAddresses[index]}`]: new Interface(curr) }; + else + return acc; + }, {}); + } + catch (error) { + console.log('parseTransactionsCb Error:', error); + interfaces.value = {}; + } + } + useSignalEffect(() => { + if (interfaces.value && bundle.value) { + parseTransactions(); + compareWithInterceptor(); + } + if (provider.value && provider.value.isInterceptor && !interceptorComparison.value.intervalId) + createCompareInterval(); + }); + const parseTransactions = async () => { + if (!bundle.value) + return; + decodedTransactions.value = bundle.value.transactions.map((tx) => { + if (tx.to && tx.input && tx.input.length > 0) { + const contractAddr = addressString(tx.to); + const txDescription = interfaces.value[contractAddr] ? interfaces.value[contractAddr].parseTransaction({ value: tx.value ?? undefined, data: tx.input.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '0x') }) : null; + return txDescription ? formatTransactionDescription(txDescription) : null; + } + return null; + }); + }; + const compare = async () => { + if (!provider.value || !provider.value.isInterceptor || !bundle.value) + return false; + try { + // fetch stack from Interceptor + const { payload } = await provider.value.provider.send('interceptor_getSimulationStack', ['1.0.0']); + const tryParse = GetSimulationStackReply.safeParse(payload); + if (!tryParse.success) + return false; + let parsedInterceptorTransactions = TransactionList.parse(serialize(GetSimulationStackReply, tryParse.value).map(({ from, to, value, input, gasLimit, chainId }) => ({ from, to, value, input, gasLimit, chainId }))); + if (parsedInterceptorTransactions.length === 0) + return false; + // Detect 'make me rich' + if (parsedInterceptorTransactions.length >= 2 && parsedInterceptorTransactions[0].to === parsedInterceptorTransactions[1].from && parsedInterceptorTransactions[0].value === parseEther('200000')) { + const fundingAddrr = parsedInterceptorTransactions[0].from; + parsedInterceptorTransactions = parsedInterceptorTransactions.map(tx => tx.from === fundingAddrr ? { ...tx, from: 'FUNDING' } : tx); + } + // Compare + const interceptorValue = TransactionList.serialize(parsedInterceptorTransactions.filter(tx => tx.from !== 'FUNDING')); + const bouquetValue = TransactionList.serialize(bundle.value.transactions.filter(tx => tx.from !== 'FUNDING')); + return JSON.stringify(interceptorValue) !== JSON.stringify(bouquetValue); + } + catch { + return false; + } + }; + const compareWithInterceptor = async () => { + const different = await compare(); + interceptorComparison.value = { ...interceptorComparison.value, different }; + }; + async function createCompareInterval() { + if (!provider.value || !provider.value.isInterceptor) + return; + const different = await compare(); + interceptorComparison.value = { different, intervalId: setInterval(compareWithInterceptor, 20000) }; + } + return (_jsxs(_Fragment, { children: [_jsx("h2", { className: 'font-bold text-2xl', children: "Your Transactions" }), _jsxs("div", { className: 'flex flex-row gap-4', children: [_jsx(Button, { variant: 'secondary', disabled: fetchingAbis.value.value.state === 'pending', onClick: () => fetchingAbis.waitFor(fetchAbis), children: "Decode Transactions From Etherscan" }), _jsx(Button, { variant: 'secondary', onClick: copyTransactions, children: _jsxs(_Fragment, { children: ["Copy Transaction List", _jsx("svg", { className: 'h-8 inline-block', "aria-hidden": 'true', fill: 'none', stroke: 'currentColor', "stroke-width": '1.5', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', children: _jsx("path", { d: 'M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6', "stroke-linecap": 'round', "stroke-linejoin": 'round' }) })] }) })] }), interceptorComparison.value.different ? _jsx(SingleNotice, { variant: 'warn', title: 'Potentially Outdated Transaction List', description: _jsxs(_Fragment, { children: ["The transactions imported in Bouquet differ from the current simulation in The Interceptor extension. ", _jsx("button", { onClick: () => importFromInterceptor(bundle, provider, blockInfo, appSettings, signers), class: 'underline text-white font-semibold', children: "Import From Interceptor" }), " "] }) }) : null, _jsx("div", { class: 'flex w-full flex-col gap-2', children: bundle.value?.transactions.map((tx, index) => (_jsxs("div", { class: 'flex w-full min-h-[96px] border border-white/90', children: [_jsx("div", { class: 'flex w-24 flex-col items-center justify-center text-white', children: _jsxs("span", { class: 'text-lg font-bold', children: ["#", index] }) }), _jsxs("div", { class: 'bg-gray-500/30 flex w-full justify-center flex-col gap-2 p-4 text-sm font-semibold', children: [_jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-10 text-right', children: "From" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: tx.from !== 'FUNDING' ? addressString(tx.from) : tx.from })] }), _jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-10 text-right', children: "To" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: tx.to ? addressString(tx.to) : 'Contract Deployment' })] }), _jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-10 text-right', children: "Value" }), _jsxs("span", { class: 'bg-black px-2 py-1 font-mono font-medium', children: [EtherSymbol, formatEther(tx.value + (tx.from === 'FUNDING' && bundle.value && bundle.value.containsFundingTx ? bundle.value.totalGas * (blockInfo.value.baseFee + blockInfo.value.priorityFee) : 0n)), " + ", EtherSymbol, formatEther(tx.gasLimit * (blockInfo.value.baseFee + blockInfo.value.priorityFee)), " Gas Fee"] })] }), decodedTransactions.value[index] ? (_jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-10 text-right', children: "Data" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium w-full break-all', children: decodedTransactions.value[index] })] })) : tx.input && tx.input.length > 0 ? (_jsxs("div", { class: 'flex gap-2 items-center', children: [_jsx("span", { class: 'w-10 text-right', children: "Data" }), _jsx("span", { class: 'bg-black px-2 py-1 font-mono font-medium w-full break-all', children: tx.input.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '0x') })] })) : null] })] }))) })] })); +}; +//# sourceMappingURL=Transactions.js.map \ No newline at end of file diff --git a/docs/js/components/Transactions.js.map b/docs/js/components/Transactions.js.map new file mode 100644 index 0000000..ab7dee7 --- /dev/null +++ b/docs/js/components/Transactions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Transactions.js","sourceRoot":"","sources":["../../ts/components/Transactions.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ReadonlySignal, Signal, useSignal, useSignalEffect } from '@preact/signals'\nimport { EtherSymbol, formatEther, getAddress, Interface, parseEther, TransactionDescription } from 'ethers'\nimport { JSXInternal } from 'preact/src/jsx.js'\nimport { AppSettings, BlockInfo, Bundle, serialize, Signers } from '../types/types.js'\nimport { NETWORKS } from '../constants.js'\nimport { ProviderStore } from '../library/provider.js'\nimport { Button } from './Button.js'\nimport { useAsyncState } from '../library/asyncState.js'\nimport { TransactionList } from '../types/bouquetTypes.js'\nimport { SingleNotice } from './Warns.js'\nimport { GetSimulationStackReply } from '../types/interceptorTypes.js'\nimport { addressString } from '../library/utils.js'\nimport { importFromInterceptor } from './Import.js'\nimport { EtherscanGetABIResult, EtherscanSourceCodeResult } from '../types/apiTypes.js'\n\nfunction formatTransactionDescription(tx: TransactionDescription) {\n\tif (tx.fragment.inputs.length === 0) return <>{`${tx.name}()`}\n\tconst params = tx.fragment.inputs.map((y, index) =>

{`${y.name}: ${tx.args[index].toString()}`}

)\n\treturn (\n\t\t<>\n\t\t\t

{`${tx.name}(`}

\n\t\t\t{params}\n\t\t\t

)

\n\t\t\n\t)\n}\n\nexport const Transactions = ({\n\tprovider,\n\tbundle,\n\tblockInfo,\n\tappSettings,\n\tsigners\n}: {\n\tprovider: Signal\n\tbundle: Signal\n\tblockInfo: Signal\n\tsigners: Signal\n\tappSettings: Signal\n\tfundingAmountMin: ReadonlySignal\n}) => {\n\tconst interfaces = useSignal<{ [address: string]: Interface }>({})\n\tconst decodedTransactions = useSignal<(JSXInternal.Element | null)[]>([])\n\tconst interceptorComparison = useSignal<{ different: boolean, intervalId?: ReturnType }>({ different: true })\n\n\tfunction copyTransactions() {\n\t\tif (!bundle.value) return\n\t\tconst parsedList = TransactionList.safeSerialize(bundle.value.transactions)\n\t\tif ('success' in parsedList && parsedList.success) navigator.clipboard.writeText(JSON.stringify(parsedList.value, null, 2))\n\t}\n\n\tconst fetchingAbis = useAsyncState()\n\n\tasync function fetchAbis() {\n\t\tif (!bundle.value || !bundle.value.transactions) return\n\t\ttry {\n\t\t\tconst uniqueAddresses = [...new Set(bundle.value.transactions.map((tx) => tx.to ? addressString(tx.to) : null ).filter(addr => addr))] as string[]\n\t\t\tconst abis: (string | undefined)[] = []\n\n\t\t\tconst requests = await Promise.all(\n\t\t\t\tuniqueAddresses.map((address) =>\n\t\t\t\t\tfetch(\n\t\t\t\t\t\t`https://api${appSettings.peek().simulationRelayEndpoint === NETWORKS['5'].simulationRelay ? '-goerli' : ''\n\t\t\t\t\t\t}.etherscan.io/api?module=contract&action=getsourcecode&address=${getAddress(address.toLowerCase())}&apiKey=PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8`,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst sourcecodeResults = await Promise.all(requests.map((request) => request.json()))\n\t\t\tconst parsedSourceCode = sourcecodeResults.map(x => EtherscanSourceCodeResult.safeParse(x))\n\n\t\t\t// Extract ABI from getSourceCode request if not proxy, otherwise attempt to fetch ABI of implementation\n\t\t\tfor (const contract of parsedSourceCode) {\n\t\t\t\tif (contract.success == false || contract.value.status !== '1') abis.push(undefined)\n\t\t\t\telse {\n\t\t\t\t\tif (contract.value.result[0].Proxy === '1' && contract.value.result[0].Implementation !== '') {\n\t\t\t\t\t\tconst implReq = await fetch(`https://api${appSettings.peek().simulationRelayEndpoint === NETWORKS['5'].simulationRelay ? '-goerli' : ''}.etherscan.io/api?module=contract&action=getabi&address=${addressString(contract.value.result[0].Implementation)}&apiKey=PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8`)\n\t\t\t\t\t\tconst implResult = EtherscanGetABIResult.safeParse(await implReq.json())\n\t\t\t\t\t\tabis.push(implResult.success && implResult.value.status === '1' ? implResult.value.result : undefined)\n\t\t\t\t\t} else abis.push(contract.value.result[0].ABI && contract.value.result[0].ABI !== 'Contract source code not verified' ? contract.value.result[0].ABI : undefined)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinterfaces.value = abis.reduce((acc, curr, index) => {\n\t\t\t\tif (curr) return { ...acc, [`${uniqueAddresses[index]}`]: new Interface(curr) }\n\t\t\t\telse return acc\n\t\t\t}, {})\n\t\t} catch (error) {\n\t\t\tconsole.log('parseTransactionsCb Error:', error)\n\t\t\tinterfaces.value = {}\n\t\t}\n\t}\n\n\tuseSignalEffect(() => {\n\t\tif (interfaces.value && bundle.value) {\n\t\t\tparseTransactions()\n\t\t\tcompareWithInterceptor()\n\t\t}\n\t\tif (provider.value && provider.value.isInterceptor && !interceptorComparison.value.intervalId) createCompareInterval()\n\t})\n\n\tconst parseTransactions = async () => {\n\t\tif (!bundle.value) return\n\t\tdecodedTransactions.value = bundle.value.transactions.map((tx) => {\n\t\t\tif (tx.to && tx.input && tx.input.length > 0) {\n\t\t\t\tconst contractAddr = addressString(tx.to)\n\t\t\t\tconst txDescription = interfaces.value[contractAddr] ? interfaces.value[contractAddr].parseTransaction({ value: tx.value ?? undefined, data: tx.input.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '0x') }) : null\n\t\t\t\treturn txDescription ? formatTransactionDescription(txDescription) : null\n\t\t\t}\n\t\t\treturn null\n\t\t})\n\t}\n\n\tconst compare = async () => {\n\t\tif (!provider.value || !provider.value.isInterceptor || !bundle.value) return false\n\t\ttry {\n\t\t\t// fetch stack from Interceptor\n\t\t\tconst { payload } = await provider.value.provider.send('interceptor_getSimulationStack', ['1.0.0'])\n\t\t\tconst tryParse = GetSimulationStackReply.safeParse(payload)\n\t\t\tif (!tryParse.success) return false\n\t\t\tlet parsedInterceptorTransactions = TransactionList.parse(serialize(GetSimulationStackReply, tryParse.value).map(({ from, to, value, input, gasLimit, chainId }) => ({ from, to, value, input, gasLimit, chainId })))\n\t\t\tif (parsedInterceptorTransactions.length === 0) return false\n\n\t\t\t// Detect 'make me rich'\n\t\t\tif (parsedInterceptorTransactions.length >= 2 && parsedInterceptorTransactions[0].to === parsedInterceptorTransactions[1].from && parsedInterceptorTransactions[0].value === parseEther('200000')) {\n\t\t\t\tconst fundingAddrr = parsedInterceptorTransactions[0].from\n\t\t\t\tparsedInterceptorTransactions = parsedInterceptorTransactions.map(tx => tx.from === fundingAddrr ? { ...tx, from: 'FUNDING' } : tx)\n\t\t\t}\n\n\t\t\t// Compare\n\t\t\tconst interceptorValue = TransactionList.serialize(parsedInterceptorTransactions.filter(tx => tx.from !== 'FUNDING'))\n\t\t\tconst bouquetValue = TransactionList.serialize(bundle.value.transactions.filter(tx => tx.from !== 'FUNDING'))\n\t\t\treturn JSON.stringify(interceptorValue) !== JSON.stringify(bouquetValue)\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tconst compareWithInterceptor = async () => {\n\t\tconst different = await compare()\n\t\tinterceptorComparison.value = { ...interceptorComparison.value, different }\n\t}\n\n\tasync function createCompareInterval() {\n\t\tif (!provider.value || !provider.value.isInterceptor) return;\n\t\tconst different = await compare()\n\t\tinterceptorComparison.value = { different, intervalId: setInterval(compareWithInterceptor, 20000)}\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t

Your Transactions

\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t\t{interceptorComparison.value.different ? The transactions imported in Bouquet differ from the current simulation in The Interceptor extension. } /> : null}\n\t\t\t
\n\t\t\t\t{bundle.value?.transactions.map((tx, index) => (\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t#{index}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\tFrom\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{tx.from !== 'FUNDING' ? addressString(tx.from) : tx.from}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\tTo\n\t\t\t\t\t\t\t\t{tx.to ? addressString(tx.to) : 'Contract Deployment'}\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\tValue\n\t\t\t\t\t\t\t\t{EtherSymbol}{formatEther(tx.value + (tx.from === 'FUNDING' && bundle.value && bundle.value.containsFundingTx ? bundle.value.totalGas * (blockInfo.value.baseFee + blockInfo.value.priorityFee): 0n))} + {EtherSymbol}{formatEther(tx.gasLimit * (blockInfo.value.baseFee + blockInfo.value.priorityFee))} Gas Fee\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{decodedTransactions.value[index] ? (\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\tData\n\t\t\t\t\t\t\t\t\t{decodedTransactions.value[index]}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t) : tx.input && tx.input.length > 0 ? (\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\tData\n\t\t\t\t\t\t\t\t\t{tx.input.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '0x')}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t))}\n\t\t\t
\n\t\t\n\t)\n}\n"]} \ No newline at end of file diff --git a/docs/js/components/Warns.d.ts b/docs/js/components/Warns.d.ts new file mode 100644 index 0000000..a297519 --- /dev/null +++ b/docs/js/components/Warns.d.ts @@ -0,0 +1,7 @@ +import { JSX } from 'preact/jsx-runtime'; +export declare const SingleNotice: ({ variant, title, description }: { + variant: 'warn' | 'error' | 'success'; + title: string; + description?: string | JSX.Element | undefined; +}) => JSX.Element; +//# sourceMappingURL=Warns.d.ts.map \ No newline at end of file diff --git a/docs/js/components/Warns.d.ts.map b/docs/js/components/Warns.d.ts.map new file mode 100644 index 0000000..8db2f1f --- /dev/null +++ b/docs/js/components/Warns.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Warns.d.ts","sourceRoot":"","sources":["../../ts/components/Warns.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAExC,eAAO,MAAM,YAAY;aAAgD,MAAM,GAAG,OAAO,GAAG,SAAS;WAAS,MAAM;;iBAmBnH,CAAA"} \ No newline at end of file diff --git a/docs/js/components/Warns.js b/docs/js/components/Warns.js new file mode 100644 index 0000000..88bf271 --- /dev/null +++ b/docs/js/components/Warns.js @@ -0,0 +1,15 @@ +import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime"; +export const SingleNotice = ({ variant, title, description }) => { + const variantColors = { + warn: 'border-orange-400/50 bg-orange-400/10', + error: 'border-red-400/50 bg-red-400/10', + success: 'border-green-400/50 bg-green-400/10' + }; + const variantEmoji = { + warn: '⚠', + error: '🛑', + success: '🎉' + }; + return (_jsxs("div", { class: `flex items-center items-center border ${variantColors[variant]} px-4 py-2 gap-4`, children: [_jsx("span", { class: 'text-2xl', children: variantEmoji[variant] }), _jsxs("div", { class: 'py-3 flex-grow', children: [_jsx("h3", { class: 'font-lg font-semibold', children: title }), description ? (_jsx("div", { class: 'leading-tight text-white/75 break-all text-sm', children: description })) : null] })] })); +}; +//# sourceMappingURL=Warns.js.map \ No newline at end of file diff --git a/docs/js/components/Warns.js.map b/docs/js/components/Warns.js.map new file mode 100644 index 0000000..6bc115e --- /dev/null +++ b/docs/js/components/Warns.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Warns.js","sourceRoot":"","sources":["../../ts/components/Warns.tsx"],"names":[],"mappings":";AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAgG,EAAE,EAAE;IAC7J,MAAM,aAAa,GAAG;QACrB,IAAI,EAAE,uCAAuC;QAC7C,KAAK,EAAE,iCAAiC;QACxC,OAAO,EAAE,qCAAqC;KAC9C,CAAA;IACD,MAAM,YAAY,GAAG;QACpB,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,IAAI;KACb,CAAA;IAED,OAAO,CAAC,eAAK,KAAK,EAAE,yCAAyC,aAAa,CAAC,OAAO,CAAC,kBAAkB,aACpG,eAAM,KAAK,EAAC,UAAU,YAAE,YAAY,CAAC,OAAO,CAAC,GAAQ,EACrD,eAAK,KAAK,EAAC,gBAAgB,aAC1B,aAAI,KAAK,EAAC,uBAAuB,YAAE,KAAK,GAAM,EAC7C,WAAW,CAAC,CAAC,CAAC,CAAC,cAAK,KAAK,EAAC,+CAA+C,YAAE,WAAW,GAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IACjG,IACD,CAAC,CAAA;AACR,CAAC,CAAA","sourcesContent":["import { JSX } from 'preact/jsx-runtime'\n\nexport const SingleNotice = ({ variant, title, description }: { variant: 'warn' | 'error' | 'success', title: string, description?: string | JSX.Element }) => {\n\tconst variantColors = {\n\t\twarn: 'border-orange-400/50 bg-orange-400/10',\n\t\terror: 'border-red-400/50 bg-red-400/10',\n\t\tsuccess: 'border-green-400/50 bg-green-400/10'\n\t}\n\tconst variantEmoji = {\n\t\twarn: '⚠',\n\t\terror: '🛑',\n\t\tsuccess: '🎉'\n\t}\n\n\treturn (
\n\t\t{variantEmoji[variant]}\n\t\t
\n\t\t\t

{title}

\n\t\t\t{description ? (
{description}
) : null}\n\t\t
\n\t
)\n}\n"]} \ No newline at end of file diff --git a/docs/js/constants.d.ts b/docs/js/constants.d.ts new file mode 100644 index 0000000..04de630 --- /dev/null +++ b/docs/js/constants.d.ts @@ -0,0 +1,9 @@ +export declare const NETWORKS: { + [chainId: string]: { + simulationRelay: string; + submissionRelay: string; + blockExplorer: string; + rpcUrl: string; + }; +}; +//# sourceMappingURL=constants.d.ts.map \ No newline at end of file diff --git a/docs/js/constants.d.ts.map b/docs/js/constants.d.ts.map new file mode 100644 index 0000000..30e449d --- /dev/null +++ b/docs/js/constants.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../ts/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,EAAE;IAAE,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAGtI,CAAA"} \ No newline at end of file diff --git a/docs/js/constants.js b/docs/js/constants.js new file mode 100644 index 0000000..817e06f --- /dev/null +++ b/docs/js/constants.js @@ -0,0 +1,5 @@ +export const NETWORKS = { + '1': { simulationRelay: 'https://relay.dark.florist', submissionRelay: 'https://rpc.titanbuilder.xyz', blockExplorer: 'https://etherscan.io/', rpcUrl: 'https://rpc.dark.florist/flipcardtrustone' }, + '5': { simulationRelay: 'https://relay-goerli.dark.florist', submissionRelay: 'https://relay-goerli.dark.florist', blockExplorer: 'https://goerli.etherscan.io/', rpcUrl: 'https://rpc-goerli.dark.florist/flipcardtrustone' } +}; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/docs/js/constants.js.map b/docs/js/constants.js.map new file mode 100644 index 0000000..6876c71 --- /dev/null +++ b/docs/js/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","sourceRoot":"","sources":["../ts/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAsH;IAC1I,GAAG,EAAE,EAAE,eAAe,EAAE,4BAA4B,EAAE,eAAe,EAAE,8BAA8B,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,EAAE,2CAA2C,EAAE;IACpM,GAAG,EAAE,EAAE,eAAe,EAAE,mCAAmC,EAAE,eAAe,EAAE,mCAAmC,EAAG,aAAa,EAAE,8BAA8B,EAAE,MAAM,EAAE,kDAAkD,EAAE;CAC/N,CAAA","sourcesContent":["export const NETWORKS: { [chainId: string]: { simulationRelay: string, submissionRelay: string, blockExplorer: string, rpcUrl: string }} = {\n\t'1': { simulationRelay: 'https://relay.dark.florist', submissionRelay: 'https://rpc.titanbuilder.xyz', blockExplorer: 'https://etherscan.io/', rpcUrl: 'https://rpc.dark.florist/flipcardtrustone' },\n\t'5': { simulationRelay: 'https://relay-goerli.dark.florist', submissionRelay: 'https://relay-goerli.dark.florist', blockExplorer: 'https://goerli.etherscan.io/', rpcUrl: 'https://rpc-goerli.dark.florist/flipcardtrustone' }\n}\n"]} \ No newline at end of file diff --git a/docs/js/index.d.ts b/docs/js/index.d.ts new file mode 100644 index 0000000..e26a57a --- /dev/null +++ b/docs/js/index.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/docs/js/index.d.ts.map b/docs/js/index.d.ts.map new file mode 100644 index 0000000..87f1b8c --- /dev/null +++ b/docs/js/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../ts/index.tsx"],"names":[],"mappings":""} \ No newline at end of file diff --git a/docs/js/index.js b/docs/js/index.js new file mode 100644 index 0000000..8f37267 --- /dev/null +++ b/docs/js/index.js @@ -0,0 +1,5 @@ +import { jsx as _jsx } from "preact/jsx-runtime"; +import { render } from 'preact'; +import { App } from './components/App.js'; +render(_jsx(App, {}), document.body, document.querySelector('main')); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/docs/js/index.js.map b/docs/js/index.js.map new file mode 100644 index 0000000..ba065d4 --- /dev/null +++ b/docs/js/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../ts/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AAEzC,MAAM,CAAC,KAAC,GAAG,KAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAgB,CAAC,CAAA","sourcesContent":["import { render } from 'preact'\nimport { App } from './components/App.js'\n\nrender(, document.body, document.querySelector('main') as HTMLElement)\n"]} \ No newline at end of file diff --git a/docs/js/library/DataURLCache.d.ts b/docs/js/library/DataURLCache.d.ts new file mode 100644 index 0000000..b03b3fb --- /dev/null +++ b/docs/js/library/DataURLCache.d.ts @@ -0,0 +1,7 @@ +export declare class DataURLCache { + private readonly dataURLs; + has: (key: string) => boolean; + get: (key: string) => string | undefined; + set: (image: string, key: string) => string; +} +//# sourceMappingURL=DataURLCache.d.ts.map \ No newline at end of file diff --git a/docs/js/library/DataURLCache.d.ts.map b/docs/js/library/DataURLCache.d.ts.map new file mode 100644 index 0000000..8770db6 --- /dev/null +++ b/docs/js/library/DataURLCache.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"DataURLCache.d.ts","sourceRoot":"","sources":["../../ts/library/DataURLCache.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAC9C,GAAG,QAAS,MAAM,aAA2B;IAC7C,GAAG,QAAS,MAAM,wBAA2B;IAC7C,GAAG,UAAW,MAAM,OAAO,MAAM,YAIvC;CACD"} \ No newline at end of file diff --git a/docs/js/library/DataURLCache.js b/docs/js/library/DataURLCache.js new file mode 100644 index 0000000..6e34024 --- /dev/null +++ b/docs/js/library/DataURLCache.js @@ -0,0 +1,15 @@ +const CACHE_SIZE = 100; +export class DataURLCache { + constructor() { + this.dataURLs = new Map(); + this.has = (key) => this.dataURLs.has(key); + this.get = (key) => this.dataURLs.get(key); + this.set = (image, key) => { + if (this.dataURLs.size > CACHE_SIZE) + this.dataURLs.delete(this.dataURLs.keys().next().value); + this.dataURLs.set(key, image); + return image; + }; + } +} +//# sourceMappingURL=DataURLCache.js.map \ No newline at end of file diff --git a/docs/js/library/DataURLCache.js.map b/docs/js/library/DataURLCache.js.map new file mode 100644 index 0000000..29b8651 --- /dev/null +++ b/docs/js/library/DataURLCache.js.map @@ -0,0 +1 @@ +{"version":3,"file":"DataURLCache.js","sourceRoot":"","sources":["../../ts/library/DataURLCache.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,GAAG,CAAA;AAEtB,MAAM,OAAO,YAAY;IAAzB;QACkB,aAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;QAC9C,QAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7C,QAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7C,QAAG,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE;YAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,UAAU;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAA;YAC5F,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAC7B,OAAO,KAAK,CAAA;QACb,CAAC,CAAA;IACF,CAAC;CAAA","sourcesContent":["const CACHE_SIZE = 100\n\nexport class DataURLCache {\n\tprivate readonly dataURLs = new Map()\n\tpublic has = (key: string) => this.dataURLs.has(key)\n\tpublic get = (key: string) => this.dataURLs.get(key)\n\tpublic set = (image: string, key: string) => {\n\t\tif (this.dataURLs.size > CACHE_SIZE) this.dataURLs.delete(this.dataURLs.keys().next().value)\n\t\tthis.dataURLs.set(key, image)\n\t\treturn image\n\t}\n}\n"]} \ No newline at end of file diff --git a/docs/js/library/asyncState.d.ts b/docs/js/library/asyncState.d.ts new file mode 100644 index 0000000..2439ed4 --- /dev/null +++ b/docs/js/library/asyncState.d.ts @@ -0,0 +1,23 @@ +import { Signal } from '@preact/signals'; +export type Inactive = { + state: 'inactive'; +}; +export type Pending = { + state: 'pending'; +}; +export type Resolved = { + state: 'resolved'; + value: T; +}; +export type Rejected = { + state: 'rejected'; + error: Error; +}; +export type AsyncProperty = Inactive | Pending | Resolved | Rejected; +export type AsyncState = { + value: Signal>; + waitFor: (resolver: () => Promise) => void; + reset: () => void; +}; +export declare function useAsyncState(): AsyncState; +//# sourceMappingURL=asyncState.d.ts.map \ No newline at end of file diff --git a/docs/js/library/asyncState.d.ts.map b/docs/js/library/asyncState.d.ts.map new file mode 100644 index 0000000..0fc3ed6 --- /dev/null +++ b/docs/js/library/asyncState.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"asyncState.d.ts","sourceRoot":"","sources":["../../ts/library/asyncState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,MAAM,iBAAiB,CAAA;AACnD,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,CAAA;AAC5C,MAAM,MAAM,OAAO,GAAG;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAA;AAC1C,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAA;AACzD,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAA;AAC1D,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAA;AAC1E,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAA;AAEjI,wBAAgB,aAAa,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAwChD"} \ No newline at end of file diff --git a/docs/js/library/asyncState.js b/docs/js/library/asyncState.js new file mode 100644 index 0000000..8bc4a49 --- /dev/null +++ b/docs/js/library/asyncState.js @@ -0,0 +1,42 @@ +import { useSignal } from '@preact/signals'; +export function useAsyncState() { + function getCaptureAndCancelOthers() { + // delete previously captured signal so any pending async work will no-op when they resolve + delete captureContainer.peek().result; + // capture the signal in a new object so we can delete it later if it is interrupted + captureContainer.value = { result }; + return captureContainer.peek(); + } + async function activate(resolver) { + const capture = getCaptureAndCancelOthers(); + // we need to read the property out of the capture every time we look at it, in case it is deleted asynchronously + function setCapturedResult(newResult) { + const result = capture.result; + if (result === undefined) + return; + result.value = newResult; + } + try { + const pendingState = { state: 'pending' }; + setCapturedResult(pendingState); + const resolvedValue = await resolver(); + const resolvedState = { state: 'resolved', value: resolvedValue }; + setCapturedResult(resolvedState); + } + catch (unknownError) { + const error = unknownError instanceof Error ? unknownError : typeof unknownError === 'string' ? new Error(unknownError) : new Error(`Unknown error occurred.\n${JSON.stringify(unknownError)}`); + const rejectedState = { state: 'rejected', error }; + setCapturedResult(rejectedState); + } + } + function reset() { + const result = getCaptureAndCancelOthers().result; + if (result === undefined) + return; + result.value = { state: 'inactive' }; + } + const result = useSignal({ state: 'inactive' }); + const captureContainer = useSignal({}); + return { value: result, waitFor: resolver => activate(resolver), reset }; +} +//# sourceMappingURL=asyncState.js.map \ No newline at end of file diff --git a/docs/js/library/asyncState.js.map b/docs/js/library/asyncState.js.map new file mode 100644 index 0000000..e889c00 --- /dev/null +++ b/docs/js/library/asyncState.js.map @@ -0,0 +1 @@ +{"version":3,"file":"asyncState.js","sourceRoot":"","sources":["../../ts/library/asyncState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAQnD,MAAM,UAAU,aAAa;IAC5B,SAAS,yBAAyB;QACjC,2FAA2F;QAC3F,OAAO,gBAAgB,CAAC,IAAI,EAAE,CAAC,MAAM,CAAA;QACrC,oFAAoF;QACpF,gBAAgB,CAAC,KAAK,GAAG,EAAE,MAAM,EAAE,CAAA;QACnC,OAAO,gBAAgB,CAAC,IAAI,EAAE,CAAA;IAC/B,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,QAA0B;QACjD,MAAM,OAAO,GAAG,yBAAyB,EAAE,CAAA;QAC3C,iHAAiH;QACjH,SAAS,iBAAiB,CAAC,SAA2B;YACrD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;YAC7B,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAM;YAChC,MAAM,CAAC,KAAK,GAAG,SAAS,CAAA;QACzB,CAAC;QACD,IAAI,CAAC;YACJ,MAAM,YAAY,GAAG,EAAE,KAAK,EAAE,SAAkB,EAAE,CAAA;YAClD,iBAAiB,CAAC,YAAY,CAAC,CAAA;YAC/B,MAAM,aAAa,GAAG,MAAM,QAAQ,EAAE,CAAA;YACtC,MAAM,aAAa,GAAG,EAAE,KAAK,EAAE,UAAmB,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA;YAC1E,iBAAiB,CAAC,aAAa,CAAC,CAAA;QACjC,CAAC;QAAC,OAAO,YAAqB,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,YAAY,YAAY,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;YAC/L,MAAM,aAAa,GAAG,EAAE,KAAK,EAAE,UAAmB,EAAE,KAAK,EAAE,CAAA;YAC3D,iBAAiB,CAAC,aAAa,CAAC,CAAA;QACjC,CAAC;IACF,CAAC;IAED,SAAS,KAAK;QACb,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAC,MAAM,CAAA;QACjD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAM;QAChC,MAAM,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;IACrC,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAmB,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAA;IACjE,MAAM,gBAAgB,GAAG,SAAS,CAAwC,EAAE,CAAC,CAAA;IAE7E,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAA;AACzE,CAAC","sourcesContent":["import { Signal, useSignal } from '@preact/signals'\nexport type Inactive = { state: 'inactive' }\nexport type Pending = { state: 'pending' }\nexport type Resolved = { state: 'resolved'; value: T }\nexport type Rejected = { state: 'rejected'; error: Error }\nexport type AsyncProperty = Inactive | Pending | Resolved | Rejected\nexport type AsyncState = { value: Signal>; waitFor: (resolver: () => Promise) => void; reset: () => void }\n\nexport function useAsyncState(): AsyncState {\n\tfunction getCaptureAndCancelOthers() {\n\t\t// delete previously captured signal so any pending async work will no-op when they resolve\n\t\tdelete captureContainer.peek().result\n\t\t// capture the signal in a new object so we can delete it later if it is interrupted\n\t\tcaptureContainer.value = { result }\n\t\treturn captureContainer.peek()\n\t}\n\n\tasync function activate(resolver: () => Promise) {\n\t\tconst capture = getCaptureAndCancelOthers()\n\t\t// we need to read the property out of the capture every time we look at it, in case it is deleted asynchronously\n\t\tfunction setCapturedResult(newResult: AsyncProperty) {\n\t\t\tconst result = capture.result\n\t\t\tif (result === undefined) return\n\t\t\tresult.value = newResult\n\t\t}\n\t\ttry {\n\t\t\tconst pendingState = { state: 'pending' as const }\n\t\t\tsetCapturedResult(pendingState)\n\t\t\tconst resolvedValue = await resolver()\n\t\t\tconst resolvedState = { state: 'resolved' as const, value: resolvedValue }\n\t\t\tsetCapturedResult(resolvedState)\n\t\t} catch (unknownError: unknown) {\n\t\t\tconst error = unknownError instanceof Error ? unknownError : typeof unknownError === 'string' ? new Error(unknownError) : new Error(`Unknown error occurred.\\n${JSON.stringify(unknownError)}`)\n\t\t\tconst rejectedState = { state: 'rejected' as const, error }\n\t\t\tsetCapturedResult(rejectedState)\n\t\t}\n\t}\n\n\tfunction reset() {\n\t\tconst result = getCaptureAndCancelOthers().result\n\t\tif (result === undefined) return\n\t\tresult.value = { state: 'inactive' }\n\t}\n\n\tconst result = useSignal>({ state: 'inactive' })\n\tconst captureContainer = useSignal<{ result?: Signal> }>({})\n\n\treturn { value: result, waitFor: resolver => activate(resolver), reset }\n}\n"]} \ No newline at end of file diff --git a/docs/js/library/bundleUtils.d.ts b/docs/js/library/bundleUtils.d.ts new file mode 100644 index 0000000..3d37217 --- /dev/null +++ b/docs/js/library/bundleUtils.d.ts @@ -0,0 +1,10 @@ +import { BrowserProvider, Signer, TransactionRequest } from 'ethers'; +import { BlockInfo, Bundle, Signers } from '../types/types.js'; +export interface FlashbotsBundleTransaction { + transaction: TransactionRequest; + signer: Signer; +} +export declare const getMaxBaseFeeInFutureBlock: (baseFee: bigint, blocksInFuture: bigint) => bigint; +export declare const signBundle: (bundle: FlashbotsBundleTransaction[], provider: BrowserProvider, blockInfo: BlockInfo, maxBaseFee: bigint) => Promise; +export declare const createBundleTransactions: (bundle: Bundle, signers: Signers, blockInfo: BlockInfo, blocksInFuture: bigint, fundingAmountMin: bigint) => Promise; +//# sourceMappingURL=bundleUtils.d.ts.map \ No newline at end of file diff --git a/docs/js/library/bundleUtils.d.ts.map b/docs/js/library/bundleUtils.d.ts.map new file mode 100644 index 0000000..de5d87f --- /dev/null +++ b/docs/js/library/bundleUtils.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"bundleUtils.d.ts","sourceRoot":"","sources":["../../ts/library/bundleUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAc,MAAM,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,EAAa,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAIzE,MAAM,WAAW,0BAA0B;IAC1C,WAAW,EAAE,kBAAkB,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;CACd;AAED,eAAO,MAAM,0BAA0B,YAAa,MAAM,kBAAkB,MAAM,WAGjF,CAAA;AAqBD,eAAO,MAAM,UAAU,WAAkB,0BAA0B,EAAE,YAAY,eAAe,aAAa,SAAS,cAAc,MAAM,sBAqBzI,CAAA;AAED,eAAO,MAAM,wBAAwB,WAC5B,MAAM,WACL,OAAO,aACL,SAAS,kBACJ,MAAM,oBACJ,MAAM,KACtB,QAAQ,0BAA0B,EAAE,CAuCtC,CAAA"} \ No newline at end of file diff --git a/docs/js/library/bundleUtils.js b/docs/js/library/bundleUtils.js new file mode 100644 index 0000000..2f352e3 --- /dev/null +++ b/docs/js/library/bundleUtils.js @@ -0,0 +1,96 @@ +import { getAddress } from 'ethers'; +import { serialize } from '../types/types.js'; +import { EthereumData } from '../types/ethereumTypes.js'; +import { addressString } from './utils.js'; +export const getMaxBaseFeeInFutureBlock = (baseFee, blocksInFuture) => { + if (blocksInFuture <= 0n) + throw new Error('blocksInFuture needs to be positive'); + return [...Array(blocksInFuture)].reduce((accumulator, _currentValue) => (accumulator * 1125n) / 1000n, baseFee) + 1n; +}; +async function getSimulatedCountsOnNetwork(provider) { + try { + const { payload } = await provider.send('interceptor_getSimulationStack', ['1.0.0']); + const result = payload.reduce((acc, curr) => { + curr.from = getAddress(curr.from); + if (curr.from in acc) + acc[curr.from] += 1; + else + acc[curr.from] = 1; + return acc; + }, {}); + return result; + } + catch (error) { + console.error('getSimulatedCountsOnNetwork error: ', error); + return {}; + } +} +export const signBundle = async (bundle, provider, blockInfo, maxBaseFee) => { + const transactions = []; + const inSimulation = await getSimulatedCountsOnNetwork(provider); + const accNonces = {}; + for (const tx of bundle) { + tx.transaction.maxPriorityFeePerGas = blockInfo.priorityFee; + tx.transaction.maxFeePerGas = blockInfo.priorityFee + maxBaseFee; + if (!tx.transaction.from) + throw new Error('BundleTransaction missing from address'); + if (!tx.transaction.chainId) + throw new Error('BundleTransaction missing chainId'); + // Fetch and increment nonces from network, reduce the fetch amount by amount of transactions made on the simulation stack + if (tx.transaction.from.toString() in accNonces) { + accNonces[tx.transaction.from.toString()] += 1; + } + else { + accNonces[tx.transaction.from.toString()] = await provider.getTransactionCount(tx.transaction.from, 'latest'); + if (tx.transaction.from.toString() in inSimulation) + accNonces[tx.transaction.from.toString()] -= inSimulation[tx.transaction.from.toString()]; + } + tx.transaction.nonce = accNonces[tx.transaction.from.toString()]; + const signedTx = await tx.signer.signTransaction(tx.transaction); + transactions.push(signedTx); + } + return transactions; +}; +export const createBundleTransactions = async (bundle, signers, blockInfo, blocksInFuture, fundingAmountMin) => { + return await Promise.all(bundle.transactions.map(async ({ from, to, gasLimit, value, input, chainId }) => { + const gasOpts = { + maxPriorityFeePerGas: blockInfo.priorityFee, + type: 2, + maxFeePerGas: blockInfo.priorityFee + getMaxBaseFeeInFutureBlock(blockInfo.baseFee, blocksInFuture), + }; + if (from === 'FUNDING') { + if (!signers.burner) + throw new Error('No burner wallet provided'); + return { + signer: signers.burner, + transaction: { + from: signers.burner.address, + ...(bundle && bundle.transactions[0].to + ? { + to: addressString(bundle.transactions[0].to), + } + : {}), + value: fundingAmountMin - 21000n * (getMaxBaseFeeInFutureBlock(blockInfo.baseFee, blocksInFuture) + blockInfo.priorityFee), + data: '0x', + gasLimit: 21000n, + chainId: Number(chainId), + ...gasOpts, + }, + }; + } + else + return { + signer: signers.bundleSigners[addressString(from)], + transaction: { + from: addressString(from), + ...(to ? { to: addressString(to) } : {}), + gasLimit, + data: serialize(EthereumData, input), + value, + chainId: Number(chainId), + ...gasOpts, + }, + }; + })); +}; +//# sourceMappingURL=bundleUtils.js.map \ No newline at end of file diff --git a/docs/js/library/bundleUtils.js.map b/docs/js/library/bundleUtils.js.map new file mode 100644 index 0000000..ab5aa54 --- /dev/null +++ b/docs/js/library/bundleUtils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bundleUtils.js","sourceRoot":"","sources":["../../ts/library/bundleUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,UAAU,EAA8B,MAAM,QAAQ,CAAA;AAChF,OAAO,EAAqB,SAAS,EAAW,MAAM,mBAAmB,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO1C,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAe,EAAE,cAAsB,EAAE,EAAE;IACrF,IAAI,cAAc,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IAChF,OAAO,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAA;AACtH,CAAC,CAAA;AAED,KAAK,UAAU,2BAA2B,CAAC,QAAyB;IACnE,IAAI,CAAC;QACJ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CACtC,gCAAgC,EAChC,CAAC,OAAO,CAAC,CACT,CAAA;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAkC,EAAE,IAAsB,EAAE,EAAE;YAC5F,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACjC,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;;gBACpC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACvB,OAAO,GAAG,CAAA;QACX,CAAC,EAAE,EAAE,CAAC,CAAA;QACN,OAAO,MAAM,CAAA;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAA;QAC3D,OAAO,EAAE,CAAA;IACV,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,MAAoC,EAAE,QAAyB,EAAE,SAAoB,EAAE,UAAkB,EAAE,EAAE;IAC7I,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,MAAM,YAAY,GAAG,MAAM,2BAA2B,CAAC,QAAQ,CAAC,CAAA;IAChE,MAAM,SAAS,GAAkC,EAAE,CAAA;IACnD,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACzB,EAAE,CAAC,WAAW,CAAC,oBAAoB,GAAG,SAAS,CAAC,WAAW,CAAA;QAC3D,EAAE,CAAC,WAAW,CAAC,YAAY,GAAG,SAAS,CAAC,WAAW,GAAG,UAAU,CAAA;QAChE,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;QACnF,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;QACjF,0HAA0H;QAC1H,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,SAAS,EAAE,CAAC;YACjD,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAA;QAC/C,CAAC;aAAM,CAAC;YACP,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,MAAM,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YAC7G,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,YAAY;gBAAE,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC9I,CAAC;QACD,EAAE,CAAC,WAAW,CAAC,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;QAChE,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,WAAW,CAAC,CAAA;QAChE,YAAY,CAAC,IAAI,CAAC,QAAkB,CAAC,CAAA;IACtC,CAAC;IACD,OAAO,YAAY,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAC5C,MAAc,EACd,OAAgB,EAChB,SAAoB,EACpB,cAAsB,EACtB,gBAAwB,EACgB,EAAE;IAC1C,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;QACxG,MAAM,OAAO,GAAG;YACf,oBAAoB,EAAE,SAAS,CAAC,WAAW;YAC3C,IAAI,EAAE,CAAC;YACP,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,0BAA0B,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,CAAC;SACnG,CAAA;QACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;YACjE,OAAO;gBACN,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,WAAW,EAAE;oBACZ,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO;oBAC5B,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;wBACtC,CAAC,CAAC;4BACD,EAAE,EAAE,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;yBAC5C;wBACD,CAAC,CAAC,EAAE,CAAC;oBACN,KAAK,EAAE,gBAAgB,GAAG,MAAM,GAAG,CAAC,0BAA0B,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC;oBAC1H,IAAI,EAAE,IAAI;oBACV,QAAQ,EAAE,MAAM;oBAChB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;oBACxB,GAAG,OAAO;iBACV;aACD,CAAA;QACF,CAAC;;YACA,OAAO;gBACN,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAClD,WAAW,EAAE;oBACZ,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC;oBACzB,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACxC,QAAQ;oBACR,IAAI,EAAE,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC;oBACpC,KAAK;oBACL,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;oBACxB,GAAG,OAAO;iBACV;aACD,CAAA;IACH,CAAC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { BrowserProvider, getAddress, Signer, TransactionRequest } from 'ethers'\nimport { BlockInfo, Bundle, serialize, Signers } from '../types/types.js'\nimport { EthereumData } from '../types/ethereumTypes.js'\nimport { addressString } from './utils.js'\n\nexport interface FlashbotsBundleTransaction {\n\ttransaction: TransactionRequest\n\tsigner: Signer\n}\n\nexport const getMaxBaseFeeInFutureBlock = (baseFee: bigint, blocksInFuture: bigint) => {\n\tif (blocksInFuture <= 0n) throw new Error('blocksInFuture needs to be positive')\n\treturn [...Array(blocksInFuture)].reduce((accumulator, _currentValue) => (accumulator * 1125n) / 1000n, baseFee) + 1n\n}\n\nasync function getSimulatedCountsOnNetwork(provider: BrowserProvider): Promise<{ [address: string]: number }> {\n\ttry {\n\t\tconst { payload } = await provider.send(\n\t\t\t'interceptor_getSimulationStack',\n\t\t\t['1.0.0']\n\t\t)\n\t\tconst result = payload.reduce((acc: { [address: string]: number }, curr: { from: string }) => {\n\t\t\tcurr.from = getAddress(curr.from)\n\t\t\tif (curr.from in acc) acc[curr.from] += 1\n\t\t\telse acc[curr.from] = 1\n\t\t\treturn acc\n\t\t}, {})\n\t\treturn result\n\t} catch (error) {\n\t\tconsole.error('getSimulatedCountsOnNetwork error: ', error)\n\t\treturn {}\n\t}\n}\n\nexport const signBundle = async (bundle: FlashbotsBundleTransaction[], provider: BrowserProvider, blockInfo: BlockInfo, maxBaseFee: bigint) => {\n\tconst transactions: string[] = []\n\tconst inSimulation = await getSimulatedCountsOnNetwork(provider)\n\tconst accNonces: { [address: string]: number } = {}\n\tfor (const tx of bundle) {\n\t\ttx.transaction.maxPriorityFeePerGas = blockInfo.priorityFee\n\t\ttx.transaction.maxFeePerGas = blockInfo.priorityFee + maxBaseFee\n\t\tif (!tx.transaction.from) throw new Error('BundleTransaction missing from address')\n\t\tif (!tx.transaction.chainId) throw new Error('BundleTransaction missing chainId')\n\t\t// Fetch and increment nonces from network, reduce the fetch amount by amount of transactions made on the simulation stack\n\t\tif (tx.transaction.from.toString() in accNonces) {\n\t\t\taccNonces[tx.transaction.from.toString()] += 1\n\t\t} else {\n\t\t\taccNonces[tx.transaction.from.toString()] = await provider.getTransactionCount(tx.transaction.from, 'latest')\n\t\t\tif (tx.transaction.from.toString() in inSimulation) accNonces[tx.transaction.from.toString()] -= inSimulation[tx.transaction.from.toString()]\n\t\t}\n\t\ttx.transaction.nonce = accNonces[tx.transaction.from.toString()]\n\t\tconst signedTx = await tx.signer.signTransaction(tx.transaction)\n\t\ttransactions.push(signedTx as string)\n\t}\n\treturn transactions\n}\n\nexport const createBundleTransactions = async (\n\tbundle: Bundle,\n\tsigners: Signers,\n\tblockInfo: BlockInfo,\n\tblocksInFuture: bigint,\n\tfundingAmountMin: bigint,\n): Promise => {\n\treturn await Promise.all(bundle.transactions.map(async ({ from, to, gasLimit, value, input, chainId }) => {\n\t\tconst gasOpts = {\n\t\t\tmaxPriorityFeePerGas: blockInfo.priorityFee,\n\t\t\ttype: 2,\n\t\t\tmaxFeePerGas: blockInfo.priorityFee + getMaxBaseFeeInFutureBlock(blockInfo.baseFee, blocksInFuture),\n\t\t}\n\t\tif (from === 'FUNDING') {\n\t\t\tif (!signers.burner) throw new Error('No burner wallet provided')\n\t\t\treturn {\n\t\t\t\tsigner: signers.burner,\n\t\t\t\ttransaction: {\n\t\t\t\t\tfrom: signers.burner.address,\n\t\t\t\t\t...(bundle && bundle.transactions[0].to\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: addressString(bundle.transactions[0].to),\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t\tvalue: fundingAmountMin - 21000n * (getMaxBaseFeeInFutureBlock(blockInfo.baseFee, blocksInFuture) + blockInfo.priorityFee),\n\t\t\t\t\tdata: '0x',\n\t\t\t\t\tgasLimit: 21000n,\n\t\t\t\t\tchainId: Number(chainId),\n\t\t\t\t\t...gasOpts,\n\t\t\t\t},\n\t\t\t}\n\t\t} else\n\t\t\treturn {\n\t\t\t\tsigner: signers.bundleSigners[addressString(from)],\n\t\t\t\ttransaction: {\n\t\t\t\t\tfrom: addressString(from),\n\t\t\t\t\t...(to ? { to: addressString(to) } : {}),\n\t\t\t\t\tgasLimit,\n\t\t\t\t\tdata: serialize(EthereumData, input),\n\t\t\t\t\tvalue,\n\t\t\t\t\tchainId: Number(chainId),\n\t\t\t\t\t...gasOpts,\n\t\t\t\t},\n\t\t\t}\n\t}))\n}\n"]} \ No newline at end of file diff --git a/docs/js/library/flashbots.d.ts b/docs/js/library/flashbots.d.ts new file mode 100644 index 0000000..a4d522e --- /dev/null +++ b/docs/js/library/flashbots.d.ts @@ -0,0 +1,83 @@ +import { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'; +import { ProviderStore } from './provider.js'; +interface TransactionSimulationBase { + txHash: string; + gasUsed: number; + gasFees: string; + gasPrice: string; + toAddress: string; + fromAddress: string; + coinbaseDiff: string; +} +export interface TransactionSimulationSuccess extends TransactionSimulationBase { + value: string; + ethSentToCoinbase: string; +} +export interface TransactionSimulationRevert extends TransactionSimulationBase { + error: string; + revert: string; +} +export type TransactionSimulation = TransactionSimulationSuccess | TransactionSimulationRevert; +export interface RelayResponseError { + error: { + message: string; + code: number; + }; +} +export interface SimulationResponseSuccess { + bundleGasPrice: bigint; + bundleHash: string; + coinbaseDiff: bigint; + ethSentToCoinbase: bigint; + gasFees: bigint; + results: Array; + totalGasUsed: number; + stateBlockNumber: number; + firstRevert?: TransactionSimulation; +} +export type SimulationResponse = SimulationResponseSuccess | RelayResponseError; +export declare function simulateBundle(bundle: Bundle, fundingAmountMin: bigint, provider: ProviderStore, signers: Signers, blockInfo: BlockInfo, appSettings: AppSettings): Promise<{ + error: { + message: any; + code: any; + }; + bundleGasPrice?: undefined; + bundleHash?: undefined; + coinbaseDiff?: undefined; + ethSentToCoinbase?: undefined; + gasFees?: undefined; + results?: undefined; + stateBlockNumber?: undefined; + totalGasUsed?: undefined; + firstRevert?: undefined; +} | { + bundleGasPrice: bigint; + bundleHash: any; + coinbaseDiff: bigint; + ethSentToCoinbase: bigint; + gasFees: bigint; + results: any; + stateBlockNumber: any; + totalGasUsed: any; + firstRevert: any; + error?: undefined; +}>; +export declare function sendBundle(bundle: Bundle, targetBlock: bigint, fundingAmountMin: bigint, provider: ProviderStore, signers: Signers, blockInfo: BlockInfo, appSettings: AppSettings): Promise<{ + bundleTransactions: { + signedTransaction: string; + hash: string; + account: string; + nonce: bigint; + }[]; + bundleHash: any; +}>; +export declare function checkBundleInclusion(transactions: { + hash: string; +}[], provider: ProviderStore): Promise<{ + transactions: { + hash: string; + }[]; + included: boolean; +}>; +export {}; +//# sourceMappingURL=flashbots.d.ts.map \ No newline at end of file diff --git a/docs/js/library/flashbots.d.ts.map b/docs/js/library/flashbots.d.ts.map new file mode 100644 index 0000000..009548a --- /dev/null +++ b/docs/js/library/flashbots.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"flashbots.d.ts","sourceRoot":"","sources":["../../ts/library/flashbots.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3E,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,UAAU,yBAAyB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,4BAA6B,SAAQ,yBAAyB;IAC9E,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,qBAAqB,GAAG,4BAA4B,GAAG,2BAA2B,CAAA;AAE9F,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE;QACN,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,MAAM,CAAA;KACZ,CAAA;CACD;AAED,MAAM,WAAW,yBAAyB;IACzC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,KAAK,CAAC,qBAAqB,CAAC,CAAA;IACrC,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,CAAC,EAAE,qBAAqB,CAAA;CACnC;AAED,MAAM,MAAM,kBAAkB,GAAG,yBAAyB,GAAG,kBAAkB,CAAA;AAE/E,wBAAsB,cAAc,CACnC,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;GAwCxB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW;;;;;;;;GAuCxL;AAED,wBAAsB,oBAAoB,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,QAAQ,EAAE,aAAa;;cAAnC,MAAM;;;GAGtE"} \ No newline at end of file diff --git a/docs/js/library/flashbots.js b/docs/js/library/flashbots.js new file mode 100644 index 0000000..df64b18 --- /dev/null +++ b/docs/js/library/flashbots.js @@ -0,0 +1,66 @@ +import { id, keccak256, Transaction } from 'ethers'; +import { createBundleTransactions, getMaxBaseFeeInFutureBlock, signBundle } from './bundleUtils.js'; +export async function simulateBundle(bundle, fundingAmountMin, provider, signers, blockInfo, appSettings) { + if (appSettings.blocksInFuture <= 0n) + throw new Error('Blocks in future is negative or zero'); + const maxBaseFee = getMaxBaseFeeInFutureBlock(blockInfo.baseFee, appSettings.blocksInFuture); + const txs = await signBundle(await createBundleTransactions(bundle, signers, blockInfo, appSettings.blocksInFuture, fundingAmountMin), provider.provider, blockInfo, maxBaseFee); + const payload = JSON.stringify({ jsonrpc: '2.0', method: 'eth_callBundle', params: [{ txs, blockNumber: `0x${blockInfo.blockNumber.toString(16)}`, stateBlockNumber: 'latest' }] }); + const flashbotsSig = `${await provider.authSigner.getAddress()}:${await provider.authSigner.signMessage(id(payload))}`; + const request = await fetch(appSettings.simulationRelayEndpoint, { method: 'POST', body: payload, headers: { 'Content-Type': 'application/json', 'X-Flashbots-Signature': flashbotsSig } }); + const response = await request.json(); + if (response.error !== undefined && response.error !== null) { + return { + error: { + message: response.error.message, + code: response.error.code, + }, + }; + } + const callResult = response.result; + return { + bundleGasPrice: BigInt(callResult.bundleGasPrice), + bundleHash: callResult.bundleHash, + coinbaseDiff: BigInt(callResult.coinbaseDiff), + ethSentToCoinbase: BigInt(callResult.ethSentToCoinbase), + gasFees: BigInt(callResult.gasFees), + results: callResult.results, + stateBlockNumber: callResult.stateBlockNumber, + totalGasUsed: callResult.results.reduce((a, b) => a + b.gasUsed, 0), + firstRevert: callResult.results.find((txSim) => 'revert' in txSim || 'error' in txSim), + }; +} +export async function sendBundle(bundle, targetBlock, fundingAmountMin, provider, signers, blockInfo, appSettings) { + if (appSettings.blocksInFuture <= 0n) + throw new Error('Blocks in future is negative or zero'); + const maxBaseFee = getMaxBaseFeeInFutureBlock(blockInfo.baseFee, appSettings.blocksInFuture); + const txs = await signBundle(await createBundleTransactions(bundle, signers, blockInfo, appSettings.blocksInFuture, fundingAmountMin), provider.provider, blockInfo, maxBaseFee); + const payload = JSON.stringify({ jsonrpc: '2.0', method: 'eth_sendBundle', params: [{ txs, blockNumber: `0x${targetBlock.toString(16)}`, revertingTxHashes: [] }] }); + const flashbotsSig = `${await provider.authSigner.getAddress()}:${await provider.authSigner.signMessage(id(payload))}`; + const request = await fetch(appSettings.submissionRelayEndpoint, { method: 'POST', body: payload, headers: { 'Content-Type': 'application/json', 'X-Flashbots-Signature': flashbotsSig } }); + const response = await request.json(); + if (response.error !== undefined && response.error !== null) { + throw { + message: response.error.message, + code: response.error.code, + }; + } + const bundleTransactions = txs.map((signedTransaction) => { + const transactionDetails = Transaction.from(signedTransaction); + return { + signedTransaction, + hash: keccak256(signedTransaction), + account: transactionDetails.from || '0x0', + nonce: BigInt(transactionDetails.nonce), + }; + }); + return { + bundleTransactions, + bundleHash: response.result.bundleHash, + }; +} +export async function checkBundleInclusion(transactions, provider) { + const receipts = await Promise.all(transactions.map((tx) => provider.provider.getTransactionReceipt(tx.hash))); + return { transactions, included: receipts.filter(x => x === null).length === 0 }; +} +//# sourceMappingURL=flashbots.js.map \ No newline at end of file diff --git a/docs/js/library/flashbots.js.map b/docs/js/library/flashbots.js.map new file mode 100644 index 0000000..77d270d --- /dev/null +++ b/docs/js/library/flashbots.js.map @@ -0,0 +1 @@ +{"version":3,"file":"flashbots.js","sourceRoot":"","sources":["../../ts/library/flashbots.ts"],"names":[],"mappings":"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","sourcesContent":["import { id, keccak256, Transaction } from 'ethers'\nimport { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js'\nimport { createBundleTransactions, getMaxBaseFeeInFutureBlock, signBundle } from './bundleUtils.js'\nimport { ProviderStore } from './provider.js'\n\ninterface TransactionSimulationBase {\n\ttxHash: string\n\tgasUsed: number\n\tgasFees: string\n\tgasPrice: string\n\ttoAddress: string\n\tfromAddress: string\n\tcoinbaseDiff: string\n}\n\nexport interface TransactionSimulationSuccess extends TransactionSimulationBase {\n\tvalue: string\n\tethSentToCoinbase: string\n}\n\nexport interface TransactionSimulationRevert extends TransactionSimulationBase {\n\terror: string\n\trevert: string\n}\n\nexport type TransactionSimulation = TransactionSimulationSuccess | TransactionSimulationRevert\n\nexport interface RelayResponseError {\n\terror: {\n\t\tmessage: string\n\t\tcode: number\n\t}\n}\n\nexport interface SimulationResponseSuccess {\n\tbundleGasPrice: bigint\n\tbundleHash: string\n\tcoinbaseDiff: bigint\n\tethSentToCoinbase: bigint\n\tgasFees: bigint\n\tresults: Array\n\ttotalGasUsed: number\n\tstateBlockNumber: number\n\tfirstRevert?: TransactionSimulation\n}\n\nexport type SimulationResponse = SimulationResponseSuccess | RelayResponseError\n\nexport async function simulateBundle(\n\tbundle: Bundle,\n\tfundingAmountMin: bigint,\n\tprovider: ProviderStore,\n\tsigners: Signers,\n\tblockInfo: BlockInfo,\n\tappSettings: AppSettings\n) {\n\tif (appSettings.blocksInFuture <= 0n) throw new Error('Blocks in future is negative or zero')\n\n\tconst maxBaseFee = getMaxBaseFeeInFutureBlock(blockInfo.baseFee, appSettings.blocksInFuture)\n\tconst txs = await signBundle(\n\t\tawait createBundleTransactions(bundle, signers, blockInfo, appSettings.blocksInFuture, fundingAmountMin),\n\t\tprovider.provider,\n\t\tblockInfo,\n\t\tmaxBaseFee,\n\t)\n\n\tconst payload = JSON.stringify({ jsonrpc: '2.0', method: 'eth_callBundle', params: [{ txs, blockNumber: `0x${blockInfo.blockNumber.toString(16)}`, stateBlockNumber: 'latest' }] })\n\tconst flashbotsSig = `${await provider.authSigner.getAddress()}:${await provider.authSigner.signMessage(id(payload))}`\n\tconst request = await fetch(appSettings.simulationRelayEndpoint,\n\t\t{ method: 'POST', body: payload, headers: { 'Content-Type': 'application/json', 'X-Flashbots-Signature': flashbotsSig } }\n\t)\n\tconst response = await request.json()\n\n\tif (response.error !== undefined && response.error !== null) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\tmessage: response.error.message,\n\t\t\t\tcode: response.error.code,\n\t\t\t},\n\t\t}\n\t}\n\n\tconst callResult = response.result\n\treturn {\n\t\tbundleGasPrice: BigInt(callResult.bundleGasPrice),\n\t\tbundleHash: callResult.bundleHash,\n\t\tcoinbaseDiff: BigInt(callResult.coinbaseDiff),\n\t\tethSentToCoinbase: BigInt(callResult.ethSentToCoinbase),\n\t\tgasFees: BigInt(callResult.gasFees),\n\t\tresults: callResult.results,\n\t\tstateBlockNumber: callResult.stateBlockNumber,\n\t\ttotalGasUsed: callResult.results.reduce((a: number, b: TransactionSimulation) => a + b.gasUsed, 0),\n\t\tfirstRevert: callResult.results.find((txSim: TransactionSimulation) => 'revert' in txSim || 'error' in txSim),\n\t}\n}\n\nexport async function sendBundle(bundle: Bundle, targetBlock: bigint, fundingAmountMin: bigint, provider: ProviderStore, signers: Signers, blockInfo: BlockInfo, appSettings: AppSettings) {\n\tif (appSettings.blocksInFuture <= 0n) throw new Error('Blocks in future is negative or zero')\n\n\tconst maxBaseFee = getMaxBaseFeeInFutureBlock(blockInfo.baseFee, appSettings.blocksInFuture)\n\tconst txs = await signBundle(\n\t\tawait createBundleTransactions(bundle, signers, blockInfo, appSettings.blocksInFuture, fundingAmountMin),\n\t\tprovider.provider,\n\t\tblockInfo,\n\t\tmaxBaseFee,\n\t)\n\n\tconst payload = JSON.stringify({ jsonrpc: '2.0', method: 'eth_sendBundle', params: [{ txs, blockNumber: `0x${targetBlock.toString(16)}`, revertingTxHashes: [] }] })\n\tconst flashbotsSig = `${await provider.authSigner.getAddress()}:${await provider.authSigner.signMessage(id(payload))}`\n\tconst request = await fetch(appSettings.submissionRelayEndpoint,\n\t\t{ method: 'POST', body: payload, headers: { 'Content-Type': 'application/json', 'X-Flashbots-Signature': flashbotsSig } }\n\t)\n\tconst response = await request.json()\n\n\tif (response.error !== undefined && response.error !== null) {\n\t\tthrow {\n\t\t\tmessage: response.error.message,\n\t\t\tcode: response.error.code,\n\t\t}\n\t}\n\n\tconst bundleTransactions = txs.map((signedTransaction) => {\n\t\tconst transactionDetails = Transaction.from(signedTransaction)\n\t\treturn {\n\t\t\tsignedTransaction,\n\t\t\thash: keccak256(signedTransaction),\n\t\t\taccount: transactionDetails.from || '0x0',\n\t\t\tnonce: BigInt(transactionDetails.nonce),\n\t\t}\n\t})\n\n\treturn {\n\t\tbundleTransactions,\n\t\tbundleHash: response.result.bundleHash,\n\t}\n}\n\nexport async function checkBundleInclusion(transactions: { hash: string }[], provider: ProviderStore) {\n\tconst receipts = await Promise.all(transactions.map((tx) => provider.provider.getTransactionReceipt(tx.hash)))\n\treturn { transactions, included: receipts.filter(x => x === null).length === 0 }\n}\n"]} \ No newline at end of file diff --git a/docs/js/library/provider.d.ts b/docs/js/library/provider.d.ts new file mode 100644 index 0000000..4a7a665 --- /dev/null +++ b/docs/js/library/provider.d.ts @@ -0,0 +1,19 @@ +import { Signal } from '@preact/signals'; +import { Block, BrowserProvider, HDNodeWallet } from 'ethers'; +import { EthereumAddress } from '../types/ethereumTypes.js'; +import { AppSettings, BlockInfo, Signers } from '../types/types.js'; +export type ProviderStore = { + provider: BrowserProvider; + _clearEvents: () => unknown; + authSigner: HDNodeWallet; + walletAddress: EthereumAddress; + chainId: bigint; + isInterceptor: boolean; +}; +export declare const connectBrowserProvider: (store: Signal, blockInfo: Signal<{ + blockNumber: bigint; + baseFee: bigint; + priorityFee: bigint; +}>, signers: Signal | undefined, appSettings: Signal) => Promise; +export declare function updateLatestBlock(block: Block, provider: Signal, blockInfo: Signal, signers: Signal | undefined): Promise; +//# sourceMappingURL=provider.d.ts.map \ No newline at end of file diff --git a/docs/js/library/provider.d.ts.map b/docs/js/library/provider.d.ts.map new file mode 100644 index 0000000..15d0eb8 --- /dev/null +++ b/docs/js/library/provider.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../ts/library/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,eAAe,EAAc,YAAY,EAAU,MAAM,QAAQ,CAAA;AAEjF,OAAO,EAAiB,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEnE,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,EAAE,eAAe,CAAA;IACzB,YAAY,EAAE,MAAM,OAAO,CAAA;IAC3B,UAAU,EAAE,YAAY,CAAC;IACzB,aAAa,EAAE,eAAe,CAAA;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAA;CACtB,CAAA;AAyCD,eAAO,MAAM,sBAAsB,UAC3B,OAAO,aAAa,GAAG,SAAS,CAAC,aAC7B,OAAO;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;CACnB,CAAC,WACO,OAAO,OAAO,CAAC,GAAG,SAAS,eACvB,OAAO,WAAW,CAAC,kBA2EhC,CAAA;AAED,wBAAsB,iBAAiB,CACtC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,EAC3C,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EAC5B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,SAAS,iBAOpC"} \ No newline at end of file diff --git a/docs/js/library/provider.js b/docs/js/library/provider.js new file mode 100644 index 0000000..86fbf8d --- /dev/null +++ b/docs/js/library/provider.js @@ -0,0 +1,118 @@ +import { batch } from '@preact/signals'; +import { BrowserProvider, getAddress, Wallet } from 'ethers'; +import { NETWORKS } from '../constants.js'; +import { AddressParser } from '../types/ethereumTypes.js'; +const addProvider = async (store, provider, clearEvents, appSettings, isInterceptor) => { + const [signer, network] = await Promise.all([provider.getSigner(), provider.getNetwork()]); + const address = await signer.getAddress(); + if (store.peek()) + removeProvider(store); + const parsedAddress = AddressParser.parse(getAddress(address)); + if (!parsedAddress.success) + throw new Error('Provider provided invalid address!'); + if (![1n, 5n].includes(network.chainId)) { + await provider.send('wallet_switchEthereumChain', [{ chainId: appSettings.peek().simulationRelayEndpoint === NETWORKS['1'].simulationRelay ? '0x1' : '0x5' }]); + } + else { + appSettings.value = { + ...appSettings.peek(), + simulationRelayEndpoint: network.chainId === 1n ? NETWORKS['1'].simulationRelay : NETWORKS['5'].simulationRelay, + submissionRelayEndpoint: network.chainId === 1n ? NETWORKS['1'].submissionRelay : NETWORKS['5'].submissionRelay, + }; + } + store.value = { + provider, + authSigner: Wallet.createRandom(), + walletAddress: parsedAddress.value, + chainId: network.chainId, + _clearEvents: clearEvents, + isInterceptor + }; +}; +const removeProvider = async (store) => { + if (store.peek()) + store.peek()?._clearEvents(); + store.value = undefined; +}; +export const connectBrowserProvider = async (store, blockInfo, signers, appSettings) => { + if (!window.ethereum || !window.ethereum.request) + throw new Error('No injected wallet detected'); + await window.ethereum.request({ method: 'eth_requestAccounts' }).catch((err) => { + if (err.code === 4001) { + throw new Error('Connect Wallet: Wallet connection rejected'); + } + else { + throw new Error(`Connect Wallet: ${JSON.stringify(err)}`); + } + }); + const provider = new BrowserProvider(window.ethereum, 'any'); + const blockCallback = async (blockNumber) => { + const block = await provider.getBlock(blockNumber); + if (block) + updateLatestBlock(block, store, blockInfo, signers); + }; + const disconnectEventCallback = () => { + removeProvider(store); + }; + const accountsChangedCallback = (accounts) => { + if (accounts.length === 0) { + removeProvider(store); + } + else { + const parsedAddress = AddressParser.parse(getAddress(accounts[0])); + if (!parsedAddress.success) + throw new Error('Provider provided invalid address!'); + store.value = store.value ? { ...store.value, walletAddress: parsedAddress.value } : undefined; + } + }; + const chainChangedCallback = async (chainId) => { + if ([1n, 5n].includes(BigInt(chainId))) { + batch(() => { + appSettings.value = { + ...appSettings.peek(), + simulationRelayEndpoint: BigInt(chainId) === 1n ? NETWORKS['1'].simulationRelay : NETWORKS['5'].simulationRelay, + submissionRelayEndpoint: BigInt(chainId) === 1n ? NETWORKS['1'].submissionRelay : NETWORKS['5'].submissionRelay + }; + store.value = store.value ? { ...store.value, chainId: BigInt(chainId) } : undefined; + }); + } + else { + store.value = store.value ? { ...store.value, chainId: BigInt(chainId) } : undefined; + } + const [accounts, block] = await Promise.all([provider.listAccounts(), provider.getBlock('latest')]); + if (accounts.length > 0 && window.ethereum) { + clearEvents(); + window.ethereum.on('disconnect', disconnectEventCallback); + window.ethereum.on('accountsChanged', accountsChangedCallback); + window.ethereum.on('chainChanged', chainChangedCallback); + provider.on('block', blockCallback); + } + accountsChangedCallback(await Promise.all(accounts.map(account => account.getAddress()))); + if (block) + updateLatestBlock(block, store, blockInfo, signers); + }; + const block = await provider.getBlock('latest'); + if (block) + await updateLatestBlock(block, store, blockInfo, signers); + window.ethereum.on('disconnect', disconnectEventCallback); + window.ethereum.on('accountsChanged', accountsChangedCallback); + window.ethereum.on('chainChanged', chainChangedCallback); + provider.on('block', blockCallback); + const clearEvents = () => { + window.ethereum?.removeListener('disconnect', disconnectEventCallback); + window.ethereum?.removeListener('accountsChanged', accountsChangedCallback); + window.ethereum?.removeListener('chainChanged', chainChangedCallback); + provider.removeListener('block', blockCallback); + }; + const [getSimulationStack] = await Promise.allSettled([window.ethereum.request({ method: 'interceptor_getSimulationStack', params: ['1.0.0'] })]); + const isInterceptor = getSimulationStack.status === 'fulfilled'; + addProvider(store, provider, clearEvents, appSettings, isInterceptor); +}; +export async function updateLatestBlock(block, provider, blockInfo, signers) { + const baseFee = block.baseFeePerGas ? block.baseFeePerGas : 0n; + blockInfo.value = { ...blockInfo.value, blockNumber: BigInt(block.number ?? 0n), baseFee }; + if (provider.value && signers && signers.value.burner) { + provider.value.provider.getBalance(signers.value.burner.address).then((burnerBalance) => signers.value = { ...signers.value, burnerBalance }); + } +} +//# sourceMappingURL=provider.js.map \ No newline at end of file diff --git a/docs/js/library/provider.js.map b/docs/js/library/provider.js.map new file mode 100644 index 0000000..860a8ca --- /dev/null +++ b/docs/js/library/provider.js.map @@ -0,0 +1 @@ +{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../ts/library/provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { batch, Signal } from '@preact/signals'\nimport { Block, BrowserProvider, getAddress, HDNodeWallet, Wallet } from 'ethers'\nimport { NETWORKS } from '../constants.js'\nimport { AddressParser, EthereumAddress } from '../types/ethereumTypes.js'\nimport { AppSettings, BlockInfo, Signers } from '../types/types.js'\n\nexport type ProviderStore = {\n\tprovider: BrowserProvider\n\t_clearEvents: () => unknown\n\tauthSigner: HDNodeWallet,\n\twalletAddress: EthereumAddress\n\tchainId: bigint,\n\tisInterceptor: boolean\n}\n\nconst addProvider = async (\n\tstore: Signal,\n\tprovider: BrowserProvider,\n\tclearEvents: () => unknown,\n\tappSettings: Signal,\n\tisInterceptor: boolean\n) => {\n\tconst [signer, network] = await Promise.all([provider.getSigner(), provider.getNetwork()])\n\tconst address = await signer.getAddress()\n\tif (store.peek()) removeProvider(store)\n\n\tconst parsedAddress = AddressParser.parse(getAddress(address))\n\tif (!parsedAddress.success) throw new Error('Provider provided invalid address!')\n\n\tif (![1n, 5n].includes(network.chainId)) {\n\t\tawait provider.send('wallet_switchEthereumChain', [{ chainId: appSettings.peek().simulationRelayEndpoint === NETWORKS['1'].simulationRelay ? '0x1' : '0x5' }])\n\t} else {\n\t\tappSettings.value = {\n\t\t\t...appSettings.peek(),\n\t\t\tsimulationRelayEndpoint: network.chainId === 1n ? NETWORKS['1'].simulationRelay : NETWORKS['5'].simulationRelay,\n\t\t\tsubmissionRelayEndpoint: network.chainId === 1n ? NETWORKS['1'].submissionRelay : NETWORKS['5'].submissionRelay,\n\t\t }\n\t}\n\n\tstore.value = {\n\t\tprovider,\n\t\tauthSigner: Wallet.createRandom(),\n\t\twalletAddress: parsedAddress.value,\n\t\tchainId: network.chainId,\n\t\t_clearEvents: clearEvents,\n\t\tisInterceptor\n\t}\n}\n\nconst removeProvider = async (store: Signal) => {\n\tif (store.peek()) store.peek()?._clearEvents()\n\tstore.value = undefined\n}\n\nexport const connectBrowserProvider = async (\n\tstore: Signal,\n\tblockInfo: Signal<{\n\t\tblockNumber: bigint\n\t\tbaseFee: bigint\n\t\tpriorityFee: bigint\n\t}>,\n\tsigners: Signal | undefined,\n\tappSettings: Signal\n) => {\n\tif (!window.ethereum || !window.ethereum.request) throw new Error('No injected wallet detected')\n\tawait window.ethereum.request({ method: 'eth_requestAccounts' }).catch((err: { code: number }) => {\n\t\tif (err.code === 4001) {\n\t\t\tthrow new Error('Connect Wallet: Wallet connection rejected')\n\t\t} else {\n\t\t\tthrow new Error(`Connect Wallet: ${JSON.stringify(err)}`)\n\t\t}\n\t})\n\n\tconst provider = new BrowserProvider(window.ethereum, 'any')\n\n\tconst blockCallback = async (blockNumber: number) => {\n\t\tconst block = await provider.getBlock(blockNumber)\n\t\tif (block) updateLatestBlock(block, store, blockInfo, signers)\n\t}\n\n\tconst disconnectEventCallback = () => {\n\t\tremoveProvider(store)\n\t}\n\tconst accountsChangedCallback = (accounts: string[]) => {\n\t\tif (accounts.length === 0) {\n\t\t\tremoveProvider(store)\n\t\t} else {\n\t\t\tconst parsedAddress = AddressParser.parse(getAddress(accounts[0]))\n\t\t\tif (!parsedAddress.success) throw new Error('Provider provided invalid address!')\n\t\t\tstore.value = store.value ? { ...store.value, walletAddress: parsedAddress.value } : undefined\n\t\t}\n\t}\n\tconst chainChangedCallback = async (chainId: string) => {\n\t\tif ([1n, 5n].includes(BigInt(chainId))) {\n\t\t\tbatch(() => {\n\t\t\t\tappSettings.value = {\n\t\t\t\t\t...appSettings.peek(),\n\t\t\t\t\tsimulationRelayEndpoint: BigInt(chainId) === 1n ? NETWORKS['1'].simulationRelay : NETWORKS['5'].simulationRelay,\n\t\t\t\t\tsubmissionRelayEndpoint: BigInt(chainId) === 1n ? NETWORKS['1'].submissionRelay : NETWORKS['5'].submissionRelay\n\t\t\t\t}\n\t\t\t\tstore.value = store.value ? { ...store.value, chainId: BigInt(chainId) } : undefined\n\t\t\t})\n\t\t} else {\n\t\t\tstore.value = store.value ? { ...store.value, chainId: BigInt(chainId) } : undefined\n\t\t}\n\n\t\tconst [accounts, block] = await Promise.all([provider.listAccounts(), provider.getBlock('latest')])\n\t\tif (accounts.length > 0 && window.ethereum) {\n\t\t\tclearEvents()\n\t\t\twindow.ethereum.on('disconnect', disconnectEventCallback)\n\t\t\twindow.ethereum.on('accountsChanged', accountsChangedCallback)\n\t\t\twindow.ethereum.on('chainChanged', chainChangedCallback)\n\t\t\tprovider.on('block', blockCallback)\n\t\t}\n\t\taccountsChangedCallback(await Promise.all(accounts.map(account => account.getAddress())))\n\t\tif (block) updateLatestBlock(block, store, blockInfo, signers)\n\t}\n\n\tconst block = await provider.getBlock('latest')\n\tif (block) await updateLatestBlock(block, store, blockInfo, signers)\n\n\twindow.ethereum.on('disconnect', disconnectEventCallback)\n\twindow.ethereum.on('accountsChanged', accountsChangedCallback)\n\twindow.ethereum.on('chainChanged', chainChangedCallback)\n\tprovider.on('block', blockCallback)\n\n\tconst clearEvents = () => {\n\t\twindow.ethereum?.removeListener('disconnect', disconnectEventCallback)\n\t\twindow.ethereum?.removeListener('accountsChanged', accountsChangedCallback)\n\t\twindow.ethereum?.removeListener('chainChanged', chainChangedCallback)\n\t\tprovider.removeListener('block', blockCallback)\n\t}\n\n\tconst [getSimulationStack] = await Promise.allSettled([window.ethereum.request({ method: 'interceptor_getSimulationStack', params: ['1.0.0'] })])\n\tconst isInterceptor = getSimulationStack.status === 'fulfilled'\n\n\taddProvider(store, provider, clearEvents, appSettings, isInterceptor)\n}\n\nexport async function updateLatestBlock(\n\tblock: Block,\n\tprovider: Signal,\n\tblockInfo: Signal,\n\tsigners: Signal | undefined,\n) {\n\tconst baseFee = block.baseFeePerGas ? block.baseFeePerGas : 0n\n\tblockInfo.value = { ...blockInfo.value, blockNumber: BigInt(block.number ?? 0n), baseFee }\n\tif (provider.value && signers && signers.value.burner) {\n\t\tprovider.value.provider.getBalance(signers.value.burner.address).then((burnerBalance) => signers.value = { ...signers.value, burnerBalance})\n\t}\n}\n"]} \ No newline at end of file diff --git a/docs/js/library/utils.d.ts b/docs/js/library/utils.d.ts new file mode 100644 index 0000000..f44307b --- /dev/null +++ b/docs/js/library/utils.d.ts @@ -0,0 +1,2 @@ +export declare function addressString(address: bigint): string; +//# sourceMappingURL=utils.d.ts.map \ No newline at end of file diff --git a/docs/js/library/utils.d.ts.map b/docs/js/library/utils.d.ts.map new file mode 100644 index 0000000..1241943 --- /dev/null +++ b/docs/js/library/utils.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../ts/library/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD"} \ No newline at end of file diff --git a/docs/js/library/utils.js b/docs/js/library/utils.js new file mode 100644 index 0000000..403fbe4 --- /dev/null +++ b/docs/js/library/utils.js @@ -0,0 +1,7 @@ +import { getAddress } from 'ethers'; +import { EthereumAddress } from '../types/ethereumTypes.js'; +import { serialize } from '../types/types.js'; +export function addressString(address) { + return getAddress(serialize(EthereumAddress, address)); +} +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/docs/js/library/utils.js.map b/docs/js/library/utils.js.map new file mode 100644 index 0000000..c61b0b7 --- /dev/null +++ b/docs/js/library/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../ts/library/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAE7C,MAAM,UAAU,aAAa,CAAC,OAAe;IAC5C,OAAO,UAAU,CAAC,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAA;AACvD,CAAC","sourcesContent":["import { getAddress } from 'ethers'\nimport { EthereumAddress } from '../types/ethereumTypes.js'\nimport { serialize } from '../types/types.js'\n\nexport function addressString(address: bigint): string {\n\treturn getAddress(serialize(EthereumAddress, address))\n}\n"]} \ No newline at end of file diff --git a/docs/js/stores.d.ts b/docs/js/stores.d.ts new file mode 100644 index 0000000..b736b68 --- /dev/null +++ b/docs/js/stores.d.ts @@ -0,0 +1,11 @@ +import { ProviderStore } from './library/provider.js'; +import { AppSettings, BlockInfo, Bundle, Signers } from './types/types.js'; +export declare function createGlobalState(): { + provider: import("@preact/signals-core").Signal; + blockInfo: import("@preact/signals-core").Signal; + bundle: import("@preact/signals-core").Signal; + appSettings: import("@preact/signals-core").Signal; + signers: import("@preact/signals-core").Signal; + fundingAmountMin: import("@preact/signals-core").ReadonlySignal; +}; +//# sourceMappingURL=stores.d.ts.map \ No newline at end of file diff --git a/docs/js/stores.d.ts.map b/docs/js/stores.d.ts.map new file mode 100644 index 0000000..c2c63e8 --- /dev/null +++ b/docs/js/stores.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../ts/stores.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAoD1E,wBAAgB,iBAAiB;;;;;;;EAqBhC"} \ No newline at end of file diff --git a/docs/js/stores.js b/docs/js/stores.js new file mode 100644 index 0000000..eeda6f1 --- /dev/null +++ b/docs/js/stores.js @@ -0,0 +1,80 @@ +import { useComputed, useSignal } from '@preact/signals'; +import { Wallet } from 'ethers'; +import { NETWORKS } from './constants.js'; +import { getMaxBaseFeeInFutureBlock } from './library/bundleUtils.js'; +import { TransactionList } from './types/bouquetTypes.js'; +import { addressString } from './library/utils.js'; +function fetchBurnerWalletFromStorage() { + const burnerPrivateKey = localStorage.getItem('wallet'); + try { + return burnerPrivateKey ? new Wallet(burnerPrivateKey) : new Wallet(Wallet.createRandom().privateKey); + } + catch { + return new Wallet(Wallet.createRandom().privateKey); + } +} +function fetchBundleFromStorage() { + const payload = JSON.parse(localStorage.getItem('payload') ?? 'null'); + if (!payload) + return undefined; + const tryParse = TransactionList.safeParse(payload); + if (!tryParse.success) { + localStorage.removeItem('payload'); + return undefined; + } + const parsed = tryParse.value; + const uniqueToAddresses = [...new Set(parsed.map(({ from }) => from))]; + const containsFundingTx = uniqueToAddresses.includes('FUNDING'); + const uniqueSigners = uniqueToAddresses.filter((address) => address !== 'FUNDING').map(address => addressString(address)); + const totalGas = parsed.reduce((sum, tx) => tx.gasLimit + sum, 0n); + const inputValue = parsed.reduce((sum, tx) => tx.from === 'FUNDING' ? tx.value + sum : sum, 0n); + return { transactions: parsed, containsFundingTx, uniqueSigners, totalGas, inputValue }; +} +function fetchSettingsFromStorage() { + const defaultValues = { blocksInFuture: 3n, priorityFee: 10n ** 9n * 3n, simulationRelayEndpoint: NETWORKS['1'].simulationRelay, submissionRelayEndpoint: NETWORKS['1'].submissionRelay }; + const custom = localStorage.getItem('bouquetSettings'); + if (!custom) { + return defaultValues; + } + else { + try { + const parsed = JSON.parse(custom); + if ('simulationRelayEndpoint' in parsed) + defaultValues.simulationRelayEndpoint = parsed.simulationRelayEndpoint; + if ('submissionRelayEndpoint' in parsed) + defaultValues.submissionRelayEndpoint = parsed.submissionRelayEndpoint; + if ('priorityFee' in parsed) + defaultValues.priorityFee = BigInt(parsed.priorityFee); + if ('blocksInFuture' in parsed) + defaultValues.blocksInFuture = BigInt(parsed.blocksInFuture); + return defaultValues; + } + catch { + return defaultValues; + } + } +} +export function createGlobalState() { + const appSettings = useSignal(fetchSettingsFromStorage()); + const provider = useSignal(undefined); + const blockInfo = useSignal({ blockNumber: 0n, baseFee: 0n, priorityFee: 10n ** 9n * 3n }); + const signers = useSignal({ burner: fetchBurnerWalletFromStorage(), burnerBalance: 0n, bundleSigners: {} }); + const bundle = useSignal(fetchBundleFromStorage()); + // Sync burnerWallet to localStorage + signers.subscribe(({ burner }) => { + if (burner) + localStorage.setItem('wallet', burner.privateKey); + else + localStorage.removeItem('wallet'); + }); + const fundingAmountMin = useComputed(() => { + if (!bundle.value) + return 0n; + if (!bundle.value.containsFundingTx) + return 0n; + const maxBaseFee = getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, appSettings.value.blocksInFuture); + return bundle.value.totalGas * (blockInfo.value.priorityFee + maxBaseFee) + bundle.value.inputValue; + }); + return { provider, blockInfo, bundle, appSettings, signers, fundingAmountMin }; +} +//# sourceMappingURL=stores.js.map \ No newline at end of file diff --git a/docs/js/stores.js.map b/docs/js/stores.js.map new file mode 100644 index 0000000..5b780c3 --- /dev/null +++ b/docs/js/stores.js.map @@ -0,0 +1 @@ +{"version":3,"file":"stores.js","sourceRoot":"","sources":["../ts/stores.ts"],"names":[],"mappings":"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","sourcesContent":["import { useComputed, useSignal } from '@preact/signals'\nimport { Wallet } from 'ethers'\nimport { NETWORKS } from './constants.js'\nimport { getMaxBaseFeeInFutureBlock } from './library/bundleUtils.js'\nimport { EthereumAddress } from './types/ethereumTypes.js'\nimport { ProviderStore } from './library/provider.js'\nimport { AppSettings, BlockInfo, Bundle, Signers } from './types/types.js'\nimport { TransactionList } from './types/bouquetTypes.js'\nimport { addressString } from './library/utils.js'\n\nfunction fetchBurnerWalletFromStorage(): Wallet {\n\tconst burnerPrivateKey = localStorage.getItem('wallet')\n\ttry {\n\t\treturn burnerPrivateKey ? new Wallet(burnerPrivateKey) : new Wallet(Wallet.createRandom().privateKey)\n\t} catch {\n\t\treturn new Wallet(Wallet.createRandom().privateKey)\n\t}\n}\n\nfunction fetchBundleFromStorage(): Bundle | undefined {\n\tconst payload = JSON.parse(localStorage.getItem('payload') ?? 'null')\n\tif (!payload) return undefined\n\tconst tryParse = TransactionList.safeParse(payload)\n\tif (!tryParse.success) {\n\t\tlocalStorage.removeItem('payload')\n\t\treturn undefined\n\t}\n\tconst parsed = tryParse.value\n\n\tconst uniqueToAddresses = [...new Set(parsed.map(({ from }) => from))]\n\tconst containsFundingTx = uniqueToAddresses.includes('FUNDING')\n\tconst uniqueSigners = uniqueToAddresses.filter((address): address is EthereumAddress => address !== 'FUNDING').map(address => addressString(address))\n\n\tconst totalGas = parsed.reduce((sum, tx) => tx.gasLimit + sum, 0n)\n\tconst inputValue = parsed.reduce((sum, tx) => tx.from === 'FUNDING' ? tx.value + sum : sum, 0n)\n\n\treturn { transactions: parsed, containsFundingTx, uniqueSigners, totalGas, inputValue }\n}\n\nfunction fetchSettingsFromStorage() {\n\tconst defaultValues: AppSettings = { blocksInFuture: 3n, priorityFee: 10n ** 9n * 3n, simulationRelayEndpoint: NETWORKS['1'].simulationRelay, submissionRelayEndpoint: NETWORKS['1'].submissionRelay };\n\tconst custom = localStorage.getItem('bouquetSettings')\n\tif (!custom) {\n\t\treturn defaultValues\n\t} else {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(custom)\n\t\t\tif ('simulationRelayEndpoint' in parsed) defaultValues.simulationRelayEndpoint = parsed.simulationRelayEndpoint\n\t\t\tif ('submissionRelayEndpoint' in parsed) defaultValues.submissionRelayEndpoint = parsed.submissionRelayEndpoint\n\t\t\tif ('priorityFee' in parsed) defaultValues.priorityFee = BigInt(parsed.priorityFee)\n\t\t\tif ('blocksInFuture' in parsed) defaultValues.blocksInFuture = BigInt(parsed.blocksInFuture)\n\t\t\treturn defaultValues\n\t\t} catch {\n\t\t\treturn defaultValues\n\t\t}\n\t}\n}\n\nexport function createGlobalState() {\n\tconst appSettings = useSignal(fetchSettingsFromStorage())\n\tconst provider = useSignal(undefined)\n\tconst blockInfo = useSignal({ blockNumber: 0n, baseFee: 0n, priorityFee: 10n ** 9n * 3n })\n\tconst signers = useSignal({ burner: fetchBurnerWalletFromStorage(), burnerBalance: 0n, bundleSigners: {} })\n\tconst bundle = useSignal(fetchBundleFromStorage())\n\n\t// Sync burnerWallet to localStorage\n\tsigners.subscribe(({ burner }) => {\n\t\tif (burner) localStorage.setItem('wallet', burner.privateKey)\n\t\telse localStorage.removeItem('wallet')\n\t})\n\n\tconst fundingAmountMin = useComputed(() => {\n\t\tif (!bundle.value) return 0n\n\t\tif (!bundle.value.containsFundingTx) return 0n\n\t\tconst maxBaseFee = getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, appSettings.value.blocksInFuture)\n\t\treturn bundle.value.totalGas * (blockInfo.value.priorityFee + maxBaseFee) + bundle.value.inputValue\n\t})\n\n\treturn { provider, blockInfo, bundle, appSettings, signers, fundingAmountMin }\n}\n"]} \ No newline at end of file diff --git a/docs/js/types/apiTypes.d.ts b/docs/js/types/apiTypes.d.ts new file mode 100644 index 0000000..e6464a1 --- /dev/null +++ b/docs/js/types/apiTypes.d.ts @@ -0,0 +1,16 @@ +import * as t from 'funtypes'; +export type EtherscanSourceCodeResult = t.Static; +export declare const EtherscanSourceCodeResult: t.Object<{ + status: t.Union<[t.Literal<"1">, t.Literal<"0">]>; + result: t.ReadonlyTuple<[t.Object<{ + ABI: t.String; + Proxy: t.Union<[t.Literal<"1">, t.Literal<"0">]>; + Implementation: t.Union<[t.Literal<"">, t.ParsedValue]>; + }, false>]>; +}, true>; +export type EtherscanGetABIResult = t.Static; +export declare const EtherscanGetABIResult: t.Object<{ + status: t.Union<[t.Literal<"1">, t.Literal<"0">]>; + result: t.String; +}, true>; +//# sourceMappingURL=apiTypes.d.ts.map \ No newline at end of file diff --git a/docs/js/types/apiTypes.d.ts.map b/docs/js/types/apiTypes.d.ts.map new file mode 100644 index 0000000..8779a5e --- /dev/null +++ b/docs/js/types/apiTypes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"apiTypes.d.ts","sourceRoot":"","sources":["../../ts/types/apiTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAK7B,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAClF,eAAO,MAAM,yBAAyB;;;;;;;QAOvB,CAAA;AAKf,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAC1E,eAAO,MAAM,qBAAqB;;;QAGnB,CAAA"} \ No newline at end of file diff --git a/docs/js/types/apiTypes.js b/docs/js/types/apiTypes.js new file mode 100644 index 0000000..da55055 --- /dev/null +++ b/docs/js/types/apiTypes.js @@ -0,0 +1,15 @@ +import * as t from 'funtypes'; +import { EthereumAddress } from './ethereumTypes.js'; +export const EtherscanSourceCodeResult = t.Object({ + status: t.Union(t.Literal('1'), t.Literal('0')), + result: t.ReadonlyTuple(t.Object({ + ABI: t.String, + Proxy: t.Union(t.Literal('1'), t.Literal('0')), + Implementation: t.Union(t.Literal(''), EthereumAddress) + })) +}).asReadonly(); +export const EtherscanGetABIResult = t.Object({ + status: t.Union(t.Literal('1'), t.Literal('0')), + result: t.String +}).asReadonly(); +//# sourceMappingURL=apiTypes.js.map \ No newline at end of file diff --git a/docs/js/types/apiTypes.js.map b/docs/js/types/apiTypes.js.map new file mode 100644 index 0000000..46190d0 --- /dev/null +++ b/docs/js/types/apiTypes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"apiTypes.js","sourceRoot":"","sources":["../../ts/types/apiTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;QAChC,GAAG,EAAE,CAAC,CAAC,MAAM;QACb,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC;KACvD,CAAC,CAAC;CACH,CAAC,CAAC,UAAU,EAAE,CAAA;AAMf,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM;CAChB,CAAC,CAAC,UAAU,EAAE,CAAA","sourcesContent":["import * as t from 'funtypes'\nimport { EthereumAddress } from './ethereumTypes.js'\n\n// Not full result definition, only entries that we consume\n// https://docs.etherscan.io/api-endpoints/contracts#get-contract-source-code-for-verified-contract-source-codes\nexport type EtherscanSourceCodeResult = t.Static\nexport const EtherscanSourceCodeResult = t.Object({\n\tstatus: t.Union(t.Literal('1'), t.Literal('0')),\n\tresult: t.ReadonlyTuple(t.Object({\n\t\tABI: t.String,\n\t\tProxy: t.Union(t.Literal('1'), t.Literal('0')),\n\t\tImplementation: t.Union(t.Literal(''), EthereumAddress)\n\t}))\n}).asReadonly()\n\n\n// Not full result definition, only entries that we consume\n// https://docs.etherscan.io/api-endpoints/contracts#get-contract-abi-for-verified-contract-source-codes\nexport type EtherscanGetABIResult = t.Static\nexport const EtherscanGetABIResult = t.Object({\n\tstatus: t.Union(t.Literal('1'), t.Literal('0')),\n\tresult: t.String\n}).asReadonly()\n\n"]} \ No newline at end of file diff --git a/docs/js/types/bouquetTypes.d.ts b/docs/js/types/bouquetTypes.d.ts new file mode 100644 index 0000000..d75c765 --- /dev/null +++ b/docs/js/types/bouquetTypes.d.ts @@ -0,0 +1,23 @@ +import * as t from 'funtypes'; +export type TransactionList = t.Static; +export declare const TransactionList: t.ReadonlyArray, t.Literal<"FUNDING">]>; + to: t.Union<[t.ParsedValue, t.Literal]>; + value: t.ParsedValue; + input: t.ParsedValue]>, Uint8Array>; + chainId: t.ParsedValue; + gasLimit: t.ParsedValue; +}, true>>; +export type PopulatedTransactionList = t.Static; +export declare const PopulatedTransactionList: t.ReadonlyArray; + to: t.Union<[t.ParsedValue, t.Literal]>; + value: t.ParsedValue; + input: t.ParsedValue]>, Uint8Array>; + chainId: t.ParsedValue; + gasLimit: t.ParsedValue; + nonce: t.ParsedValue; + maxFeePerGas: t.ParsedValue; + maxPriorityFeePerGas: t.ParsedValue; +}, true>>; +//# sourceMappingURL=bouquetTypes.d.ts.map \ No newline at end of file diff --git a/docs/js/types/bouquetTypes.d.ts.map b/docs/js/types/bouquetTypes.d.ts.map new file mode 100644 index 0000000..9360540 --- /dev/null +++ b/docs/js/types/bouquetTypes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"bouquetTypes.d.ts","sourceRoot":"","sources":["../../ts/types/bouquetTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAG7B,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAA;AAC9D,eAAO,MAAM,eAAe;;;;;;;SAOZ,CAAA;AAEhB,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAChF,eAAO,MAAM,wBAAwB;;;;;;;;;;SAUrB,CAAA"} \ No newline at end of file diff --git a/docs/js/types/bouquetTypes.js b/docs/js/types/bouquetTypes.js new file mode 100644 index 0000000..6b13534 --- /dev/null +++ b/docs/js/types/bouquetTypes.js @@ -0,0 +1,22 @@ +import * as t from 'funtypes'; +import { EthereumAddress, EthereumInput, EthereumQuantity } from './ethereumTypes.js'; +export const TransactionList = t.ReadonlyArray(t.Object({ + from: t.Union(EthereumAddress, t.Literal('FUNDING')), + to: t.Union(EthereumAddress, t.Null), + value: EthereumQuantity, + input: EthereumInput, + chainId: EthereumQuantity, + gasLimit: EthereumQuantity +}).asReadonly()); +export const PopulatedTransactionList = t.ReadonlyArray(t.Object({ + from: EthereumAddress, + to: t.Union(EthereumAddress, t.Null), + value: EthereumQuantity, + input: EthereumInput, + chainId: EthereumQuantity, + gasLimit: EthereumQuantity, + nonce: EthereumQuantity, + maxFeePerGas: EthereumQuantity, + maxPriorityFeePerGas: EthereumQuantity +}).asReadonly()); +//# sourceMappingURL=bouquetTypes.js.map \ No newline at end of file diff --git a/docs/js/types/bouquetTypes.js.map b/docs/js/types/bouquetTypes.js.map new file mode 100644 index 0000000..2e63186 --- /dev/null +++ b/docs/js/types/bouquetTypes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bouquetTypes.js","sourceRoot":"","sources":["../../ts/types/bouquetTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAC7B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGrF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IACvD,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpD,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,gBAAgB;IACvB,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,gBAAgB;IACzB,QAAQ,EAAE,gBAAgB;CAC1B,CAAC,CAAC,UAAU,EAAE,CAAC,CAAA;AAGhB,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IAChE,IAAI,EAAE,eAAe;IACrB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,gBAAgB;IACvB,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,gBAAgB;IACzB,QAAQ,EAAE,gBAAgB;IAC1B,KAAK,EAAE,gBAAgB;IACvB,YAAY,EAAE,gBAAgB;IAC9B,oBAAoB,EAAE,gBAAgB;CACtC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAA","sourcesContent":["import * as t from 'funtypes'\nimport { EthereumAddress, EthereumInput, EthereumQuantity } from './ethereumTypes.js'\n\nexport type TransactionList = t.Static\nexport const TransactionList = t.ReadonlyArray(t.Object({\n\tfrom: t.Union(EthereumAddress, t.Literal('FUNDING')),\n\tto: t.Union(EthereumAddress, t.Null),\n\tvalue: EthereumQuantity,\n\tinput: EthereumInput,\n\tchainId: EthereumQuantity,\n\tgasLimit: EthereumQuantity\n}).asReadonly())\n\nexport type PopulatedTransactionList = t.Static\nexport const PopulatedTransactionList = t.ReadonlyArray(t.Object({\n\tfrom: EthereumAddress,\n\tto: t.Union(EthereumAddress, t.Null),\n\tvalue: EthereumQuantity,\n\tinput: EthereumInput,\n\tchainId: EthereumQuantity,\n\tgasLimit: EthereumQuantity,\n\tnonce: EthereumQuantity,\n\tmaxFeePerGas: EthereumQuantity,\n\tmaxPriorityFeePerGas: EthereumQuantity\n}).asReadonly())\n"]} \ No newline at end of file diff --git a/docs/js/types/ethereumTypes.d.ts b/docs/js/types/ethereumTypes.d.ts new file mode 100644 index 0000000..378e6bc --- /dev/null +++ b/docs/js/types/ethereumTypes.d.ts @@ -0,0 +1,15 @@ +import * as t from 'funtypes'; +export declare const AddressParser: t.ParsedValue['config']; +export declare const BytesParser: t.ParsedValue['config']; +export declare const LiteralConverterParserFactory: (input: TInput, output: TOutput) => t.ParsedValue, TOutput>['config']; +export declare const EthereumQuantity: t.ParsedValue; +export type EthereumQuantity = t.Static; +export declare const EthereumData: t.ParsedValue; +export type EthereumData = t.Static; +export declare const EthereumAddress: t.ParsedValue; +export type EthereumAddress = t.Static; +export declare const EthereumBytes32: t.ParsedValue; +export type EthereumBytes32 = t.Static; +export declare const EthereumInput: t.ParsedValue]>, Uint8Array>; +export type EthereumInput = t.Static; +//# sourceMappingURL=ethereumTypes.d.ts.map \ No newline at end of file diff --git a/docs/js/types/ethereumTypes.d.ts.map b/docs/js/types/ethereumTypes.d.ts.map new file mode 100644 index 0000000..b1e0b76 --- /dev/null +++ b/docs/js/types/ethereumTypes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ethereumTypes.d.ts","sourceRoot":"","sources":["../../ts/types/ethereumTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAiB7B,eAAO,MAAM,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAanE,CAAA;AAiBD,eAAO,MAAM,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,QAAQ,CA4BrE,CAAA;AAOD,eAAO,MAAM,6BAA6B,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,QAAQ,CAQlJ,CAAA;AAED,eAAO,MAAM,gBAAgB,iCAAoC,CAAA;AACjE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAEhE,eAAO,MAAM,YAAY,qCAAmC,CAAA;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,YAAY,CAAC,CAAA;AAExD,eAAO,MAAM,eAAe,iCAAqC,CAAA;AACjE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAA;AAE9D,eAAO,MAAM,eAAe,iCAAqC,CAAA;AACjE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAA;AAE9D,eAAO,MAAM,aAAa,sEAAiE,CAAA;AAC3F,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAA"} \ No newline at end of file diff --git a/docs/js/types/ethereumTypes.js b/docs/js/types/ethereumTypes.js new file mode 100644 index 0000000..22a8178 --- /dev/null +++ b/docs/js/types/ethereumTypes.js @@ -0,0 +1,95 @@ +import * as t from 'funtypes'; +const BigIntParser = { + parse: (value) => { + if (!/^0x([a-fA-F0-9]{1,64})$/.test(value)) + return { + success: false, + message: `${value} is not a hex string encoded number.`, + }; + else + return { success: true, value: BigInt(value) }; + }, + serialize: (value) => { + if (typeof value !== 'bigint') + return { success: false, message: `${typeof value} is not a bigint.` }; + return { success: true, value: `0x${value.toString(16)}` }; + }, +}; +export const AddressParser = { + parse: (value) => { + if (!/^0x([a-fA-F0-9]{40})$/.test(value)) + return { + success: false, + message: `${value} is not a hex string encoded address.`, + }; + else + return { success: true, value: BigInt(value) }; + }, + serialize: (value) => { + if (typeof value !== 'bigint') + return { success: false, message: `${typeof value} is not a bigint.` }; + return { success: true, value: `0x${value.toString(16).padStart(40, '0')}` }; + }, +}; +const Bytes32Parser = { + parse: (value) => { + if (!/^0x([a-fA-F0-9]{64})$/.test(value)) + return { + success: false, + message: `${value} is not a hex string encoded 32 byte value.`, + }; + else + return { success: true, value: BigInt(value) }; + }, + serialize: (value) => { + if (typeof value !== 'bigint') + return { success: false, message: `${typeof value} is not a bigint.` }; + return { success: true, value: `0x${value.toString(16).padStart(64, '0')}` }; + }, +}; +export const BytesParser = { + parse: (value) => { + const match = /^(?:0x)?([a-fA-F0-9]*)$/.exec(value); + if (match === null) + return { + success: false, + message: `Expected a hex string encoded byte array with an optional '0x' prefix but received ${value}`, + }; + const normalized = match[1]; + if (normalized.length % 2) + return { + success: false, + message: `Hex string encoded byte array must be an even number of charcaters long.`, + }; + const bytes = new Uint8Array(normalized.length / 2); + for (let i = 0; i < normalized.length; i += 2) { + bytes[i / 2] = Number.parseInt(`${normalized[i]}${normalized[i + 1]}`, 16); + } + return { success: true, value: new Uint8Array(bytes) }; + }, + serialize: (value) => { + if (!(value instanceof Uint8Array)) + return { success: false, message: `${typeof value} is not a Uint8Array.` }; + let result = ''; + for (let i = 0; i < value.length; ++i) { + result += ('0' + value[i].toString(16)).slice(-2); + } + return { success: true, value: `0x${result}` }; + }, +}; +const OptionalBytesParser = { + parse: (value) => BytesParser.parse(value || '0x'), + serialize: (value) => BytesParser.serialize(value || new Uint8Array()), +}; +export const LiteralConverterParserFactory = (input, output) => { + return { + parse: (value) => (value === input ? { success: true, value: output } : { success: false, message: `${value} was expected to be literal.` }), + serialize: (value) => (value === output ? { success: true, value: input } : { success: false, message: `${value} was expected to be literal.` }), + }; +}; +export const EthereumQuantity = t.String.withParser(BigIntParser); +export const EthereumData = t.String.withParser(BytesParser); +export const EthereumAddress = t.String.withParser(AddressParser); +export const EthereumBytes32 = t.String.withParser(Bytes32Parser); +export const EthereumInput = t.Union(t.String, t.Undefined).withParser(OptionalBytesParser); +//# sourceMappingURL=ethereumTypes.js.map \ No newline at end of file diff --git a/docs/js/types/ethereumTypes.js.map b/docs/js/types/ethereumTypes.js.map new file mode 100644 index 0000000..d219b48 --- /dev/null +++ b/docs/js/types/ethereumTypes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ethereumTypes.js","sourceRoot":"","sources":["../../ts/types/ethereumTypes.ts"],"names":[],"mappings":"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","sourcesContent":["import * as t from 'funtypes'\n\nconst BigIntParser: t.ParsedValue['config'] = {\n\tparse: (value) => {\n\t\tif (!/^0x([a-fA-F0-9]{1,64})$/.test(value))\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `${value} is not a hex string encoded number.`,\n\t\t\t}\n\t\telse return { success: true, value: BigInt(value) }\n\t},\n\tserialize: (value) => {\n\t\tif (typeof value !== 'bigint') return { success: false, message: `${typeof value} is not a bigint.` }\n\t\treturn { success: true, value: `0x${value.toString(16)}` }\n\t},\n}\n\nexport const AddressParser: t.ParsedValue['config'] = {\n\tparse: (value) => {\n\t\tif (!/^0x([a-fA-F0-9]{40})$/.test(value))\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `${value} is not a hex string encoded address.`,\n\t\t\t}\n\t\telse return { success: true, value: BigInt(value) }\n\t},\n\tserialize: (value) => {\n\t\tif (typeof value !== 'bigint') return { success: false, message: `${typeof value} is not a bigint.` }\n\t\treturn { success: true, value: `0x${value.toString(16).padStart(40, '0')}` }\n\t},\n}\n\nconst Bytes32Parser: t.ParsedValue['config'] = {\n\tparse: (value) => {\n\t\tif (!/^0x([a-fA-F0-9]{64})$/.test(value))\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `${value} is not a hex string encoded 32 byte value.`,\n\t\t\t}\n\t\telse return { success: true, value: BigInt(value) }\n\t},\n\tserialize: (value) => {\n\t\tif (typeof value !== 'bigint') return { success: false, message: `${typeof value} is not a bigint.` }\n\t\treturn { success: true, value: `0x${value.toString(16).padStart(64, '0')}` }\n\t},\n}\n\nexport const BytesParser: t.ParsedValue['config'] = {\n\tparse: (value) => {\n\t\tconst match = /^(?:0x)?([a-fA-F0-9]*)$/.exec(value)\n\t\tif (match === null)\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `Expected a hex string encoded byte array with an optional '0x' prefix but received ${value}`,\n\t\t\t}\n\t\tconst normalized = match[1]\n\t\tif (normalized.length % 2)\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: `Hex string encoded byte array must be an even number of charcaters long.`,\n\t\t\t}\n\t\tconst bytes = new Uint8Array(normalized.length / 2)\n\t\tfor (let i = 0; i < normalized.length; i += 2) {\n\t\t\tbytes[i / 2] = Number.parseInt(`${normalized[i]}${normalized[i + 1]}`, 16)\n\t\t}\n\t\treturn { success: true, value: new Uint8Array(bytes) }\n\t},\n\tserialize: (value) => {\n\t\tif (!(value instanceof Uint8Array)) return { success: false, message: `${typeof value} is not a Uint8Array.` }\n\t\tlet result = ''\n\t\tfor (let i = 0; i < value.length; ++i) {\n\t\t\tresult += ('0' + value[i].toString(16)).slice(-2)\n\t\t}\n\t\treturn { success: true, value: `0x${result}` }\n\t},\n}\n\nconst OptionalBytesParser: t.ParsedValue]>, Uint8Array>['config'] = {\n\tparse: (value) => BytesParser.parse(value || '0x'),\n\tserialize: (value) => BytesParser.serialize!(value || new Uint8Array()),\n}\n\nexport const LiteralConverterParserFactory: (input: TInput, output: TOutput) => t.ParsedValue, TOutput>['config'] = (\n\tinput,\n\toutput,\n) => {\n\treturn {\n\t\tparse: (value) => (value === input ? { success: true, value: output } : { success: false, message: `${value} was expected to be literal.` }),\n\t\tserialize: (value) => (value === output ? { success: true, value: input } : { success: false, message: `${value} was expected to be literal.` }),\n\t}\n}\n\nexport const EthereumQuantity = t.String.withParser(BigIntParser)\nexport type EthereumQuantity = t.Static\n\nexport const EthereumData = t.String.withParser(BytesParser)\nexport type EthereumData = t.Static\n\nexport const EthereumAddress = t.String.withParser(AddressParser)\nexport type EthereumAddress = t.Static\n\nexport const EthereumBytes32 = t.String.withParser(Bytes32Parser)\nexport type EthereumBytes32 = t.Static\n\nexport const EthereumInput = t.Union(t.String, t.Undefined).withParser(OptionalBytesParser)\nexport type EthereumInput = t.Static\n\n"]} \ No newline at end of file diff --git a/docs/js/types/interceptorTypes.d.ts b/docs/js/types/interceptorTypes.d.ts new file mode 100644 index 0000000..99d5982 --- /dev/null +++ b/docs/js/types/interceptorTypes.d.ts @@ -0,0 +1,74 @@ +import * as t from 'funtypes'; +export type GetSimulationStackReply = t.Static; +export declare const GetSimulationStackReply: t.ReadonlyArray, "legacy">, t.ParsedValue, "legacy">]>; + from: t.ParsedValue; + nonce: t.ParsedValue; + gasPrice: t.ParsedValue; + gas: t.ParsedValue; + to: t.Union<[t.ParsedValue, t.Literal]>; + value: t.ParsedValue; + input: t.ParsedValue]>, Uint8Array>; +}, true>, t.Partial<{ + chainId: t.ParsedValue; +}, true>]>, t.Intersect<[t.Object<{ + type: t.ParsedValue, "2930">; + from: t.ParsedValue; + nonce: t.ParsedValue; + gasPrice: t.ParsedValue; + gas: t.ParsedValue; + to: t.Union<[t.ParsedValue, t.Literal]>; + value: t.ParsedValue; + input: t.ParsedValue]>, Uint8Array>; + chainId: t.ParsedValue; +}, true>, t.Partial<{ + accessList: t.ReadonlyArray; + storageKeys: t.ReadonlyArray>; + }, true>>; +}, false>]>, t.Intersect<[t.Object<{ + type: t.ParsedValue, "1559">; + from: t.ParsedValue; + nonce: t.ParsedValue; + maxFeePerGas: t.ParsedValue; + maxPriorityFeePerGas: t.ParsedValue; + gas: t.ParsedValue; + to: t.Union<[t.ParsedValue, t.Literal]>; + value: t.ParsedValue; + input: t.ParsedValue]>, Uint8Array>; + chainId: t.ParsedValue; +}, true>, t.Partial<{ + accessList: t.ReadonlyArray; + storageKeys: t.ReadonlyArray>; + }, true>>; +}, false>]>]>, t.Union<[t.Object<{ + statusCode: t.ParsedValue, "success">; + gasSpent: t.ParsedValue; + returnValue: t.ParsedValue; + events: t.ReadonlyArray; + data: t.ParsedValue]>, Uint8Array>; + topics: t.ReadonlyArray>; + }, true>>; + balanceChanges: t.ReadonlyArray; + before: t.ParsedValue; + after: t.ParsedValue; + }, true>>; +}, true>, t.Object<{ + statusCode: t.ParsedValue, "failure">; + gasSpent: t.ParsedValue; + error: t.ParsedValue; + returnValue: t.ParsedValue; +}, true>]>, t.Object<{ + realizedGasPrice: t.ParsedValue; + gasLimit: t.ParsedValue; + maxPriorityFeePerGas: t.ParsedValue; + balanceChanges: t.ReadonlyArray; + before: t.ParsedValue; + after: t.ParsedValue; + }, true>>; +}, true>]>>; +//# sourceMappingURL=interceptorTypes.d.ts.map \ No newline at end of file diff --git a/docs/js/types/interceptorTypes.d.ts.map b/docs/js/types/interceptorTypes.d.ts.map new file mode 100644 index 0000000..284b761 --- /dev/null +++ b/docs/js/types/interceptorTypes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"interceptorTypes.d.ts","sourceRoot":"","sources":["../../ts/types/interceptorTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AA4H7B,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAC9E,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAWnC,CAAA"} \ No newline at end of file diff --git a/docs/js/types/interceptorTypes.js b/docs/js/types/interceptorTypes.js new file mode 100644 index 0000000..736b6d1 --- /dev/null +++ b/docs/js/types/interceptorTypes.js @@ -0,0 +1,96 @@ +import * as t from 'funtypes'; +import { EthereumAddress, EthereumQuantity, EthereumData, EthereumBytes32, LiteralConverterParserFactory, EthereumInput, BytesParser } from './ethereumTypes.js'; +const EthereumAccessList = t.ReadonlyArray(t + .Object({ + address: EthereumAddress, + storageKeys: t.ReadonlyArray(EthereumBytes32), +}) + .asReadonly()); +const EthereumUnsignedTransactionLegacy = t.Intersect(t.Object({ + type: t.Union(t.Literal('0x0').withParser(LiteralConverterParserFactory('0x0', 'legacy')), t.Literal(undefined).withParser(LiteralConverterParserFactory(undefined, 'legacy'))), + from: EthereumAddress, + nonce: EthereumQuantity, + gasPrice: EthereumQuantity, + gas: EthereumQuantity, + to: t.Union(EthereumAddress, t.Null), + value: EthereumQuantity, + input: EthereumInput, +}).asReadonly(), t.Partial({ + chainId: EthereumQuantity, +}).asReadonly()); +const EthereumUnsignedTransaction2930 = t.Intersect(t.Object({ + type: t.Literal('0x1').withParser(LiteralConverterParserFactory('0x1', '2930')), + from: EthereumAddress, + nonce: EthereumQuantity, + gasPrice: EthereumQuantity, + gas: EthereumQuantity, + to: t.Union(EthereumAddress, t.Null), + value: EthereumQuantity, + input: EthereumInput, + chainId: EthereumQuantity, +}).asReadonly(), t.Partial({ + accessList: EthereumAccessList, +})); +const EthereumUnsignedTransaction1559 = t.Intersect(t.Object({ + type: t.Literal('0x2').withParser(LiteralConverterParserFactory('0x2', '1559')), + from: EthereumAddress, + nonce: EthereumQuantity, + maxFeePerGas: EthereumQuantity, + maxPriorityFeePerGas: EthereumQuantity, + gas: EthereumQuantity, + to: t.Union(EthereumAddress, t.Null), + value: EthereumQuantity, + input: EthereumInput, + chainId: EthereumQuantity, +}).asReadonly(), t.Partial({ + accessList: EthereumAccessList, +})); +const EthereumUnsignedTransaction = t.Union(EthereumUnsignedTransactionLegacy, EthereumUnsignedTransaction2930, EthereumUnsignedTransaction1559); +const RevertErrorParser = { + parse: (value) => { + if (!value.startsWith('Reverted ')) + return { success: true, value }; + const parseResult = BytesParser.parse(value.slice('Reverted '.length)); + if (!parseResult.success) + return parseResult; + const decoded = new TextDecoder().decode(parseResult.value); + return { success: true, value: decoded }; + }, + serialize: (value) => { + const encoded = new TextEncoder().encode(value); + const serializationResult = BytesParser.serialize(encoded); + if (!serializationResult.success) + return serializationResult; + return { success: true, value: `Reverted ${serializationResult.value}` }; + } +}; +const MulticallResponseEventLog = t.Object({ + loggersAddress: EthereumAddress, + data: EthereumInput, + topics: t.ReadonlyArray(EthereumBytes32), +}).asReadonly(); +const MulticallResponseEventLogs = t.ReadonlyArray(MulticallResponseEventLog); +const EthBalanceChanges = t.ReadonlyArray(t.Object({ + address: EthereumAddress, + before: EthereumQuantity, + after: EthereumQuantity, +}).asReadonly()); +const SingleMulticallResponse = t.Union(t.Object({ + statusCode: t.Literal(1).withParser(LiteralConverterParserFactory(1, 'success')), + gasSpent: EthereumQuantity, + returnValue: EthereumData, + events: MulticallResponseEventLogs, + balanceChanges: EthBalanceChanges, +}).asReadonly(), t.Object({ + statusCode: t.Literal(0).withParser(LiteralConverterParserFactory(0, 'failure')), + gasSpent: EthereumQuantity, + error: t.String.withParser(RevertErrorParser), + returnValue: EthereumData, +}).asReadonly()); +export const GetSimulationStackReply = t.ReadonlyArray(t.Intersect(EthereumUnsignedTransaction, SingleMulticallResponse, t.Object({ + realizedGasPrice: EthereumQuantity, + gasLimit: EthereumQuantity, + maxPriorityFeePerGas: EthereumQuantity, + balanceChanges: EthBalanceChanges +}).asReadonly())); +//# sourceMappingURL=interceptorTypes.js.map \ No newline at end of file diff --git a/docs/js/types/interceptorTypes.js.map b/docs/js/types/interceptorTypes.js.map new file mode 100644 index 0000000..cc420a9 --- /dev/null +++ b/docs/js/types/interceptorTypes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"interceptorTypes.js","sourceRoot":"","sources":["../../ts/types/interceptorTypes.ts"],"names":[],"mappings":"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","sourcesContent":["import * as t from 'funtypes'\nimport { EthereumAddress, EthereumQuantity, EthereumData, EthereumBytes32, LiteralConverterParserFactory, EthereumInput, BytesParser } from './ethereumTypes.js'\n\nconst EthereumAccessList = t.ReadonlyArray(\n\tt\n\t\t.Object({\n\t\t\taddress: EthereumAddress,\n\t\t\tstorageKeys: t.ReadonlyArray(EthereumBytes32),\n\t\t})\n\t\t.asReadonly(),\n)\ntype EthereumAccessList = t.Static\n\ntype EthereumUnsignedTransactionLegacy = t.Static\nconst EthereumUnsignedTransactionLegacy = t.Intersect(\n\tt.Object({\n\t\ttype: t.Union(\n\t\t\tt.Literal('0x0').withParser(LiteralConverterParserFactory('0x0', 'legacy' as const)),\n\t\t\tt.Literal(undefined).withParser(LiteralConverterParserFactory(undefined, 'legacy' as const)),\n\t\t),\n\t\tfrom: EthereumAddress,\n\t\tnonce: EthereumQuantity,\n\t\tgasPrice: EthereumQuantity,\n\t\tgas: EthereumQuantity,\n\t\tto: t.Union(EthereumAddress, t.Null),\n\t\tvalue: EthereumQuantity,\n\t\tinput: EthereumInput,\n\t}).asReadonly(),\n\tt.Partial({\n\t\tchainId: EthereumQuantity,\n\t}).asReadonly()\n)\n\ntype EthereumUnsignedTransaction2930 = t.Static\nconst EthereumUnsignedTransaction2930 = t.Intersect(\n\tt.Object({\n\t\ttype: t.Literal('0x1').withParser(LiteralConverterParserFactory('0x1', '2930' as const)),\n\t\tfrom: EthereumAddress,\n\t\tnonce: EthereumQuantity,\n\t\tgasPrice: EthereumQuantity,\n\t\tgas: EthereumQuantity,\n\t\tto: t.Union(EthereumAddress, t.Null),\n\t\tvalue: EthereumQuantity,\n\t\tinput: EthereumInput,\n\t\tchainId: EthereumQuantity,\n\t}).asReadonly(),\n\tt.Partial({\n\t\taccessList: EthereumAccessList,\n\t})\n)\n\ntype EthereumUnsignedTransaction1559 = t.Static\nconst EthereumUnsignedTransaction1559 = t.Intersect(\n\tt.Object({\n\t\ttype: t.Literal('0x2').withParser(LiteralConverterParserFactory('0x2', '1559' as const)),\n\t\tfrom: EthereumAddress,\n\t\tnonce: EthereumQuantity,\n\t\tmaxFeePerGas: EthereumQuantity,\n\t\tmaxPriorityFeePerGas: EthereumQuantity,\n\t\tgas: EthereumQuantity,\n\t\tto: t.Union(EthereumAddress, t.Null),\n\t\tvalue: EthereumQuantity,\n\t\tinput: EthereumInput,\n\t\tchainId: EthereumQuantity,\n\t}).asReadonly(),\n\tt.Partial({\n\t\taccessList: EthereumAccessList,\n\t})\n)\ntype EthereumUnsignedTransaction = t.Static\nconst EthereumUnsignedTransaction = t.Union(EthereumUnsignedTransactionLegacy, EthereumUnsignedTransaction2930, EthereumUnsignedTransaction1559)\n\nconst RevertErrorParser: t.ParsedValue['config'] = {\n\tparse: (value) => {\n\t\tif (!value.startsWith('Reverted ')) return { success: true, value }\n\t\tconst parseResult = BytesParser.parse(value.slice('Reverted '.length))\n\t\tif (!parseResult.success) return parseResult\n\t\tconst decoded = new TextDecoder().decode(parseResult.value)\n\t\treturn { success: true, value: decoded }\n\t},\n\tserialize: (value) => {\n\t\tconst encoded = new TextEncoder().encode(value)\n\t\tconst serializationResult = BytesParser.serialize!(encoded)\n\t\tif (!serializationResult.success) return serializationResult\n\t\treturn { success: true, value: `Reverted ${serializationResult.value}` }\n\t}\n}\n\ntype MulticallResponseEventLog = t.Static\nconst MulticallResponseEventLog = t.Object({\n\tloggersAddress: EthereumAddress,\n\tdata: EthereumInput,\n\ttopics: t.ReadonlyArray(EthereumBytes32),\n}).asReadonly()\n\ntype MulticallResponseEventLogs = t.Static\nconst MulticallResponseEventLogs = t.ReadonlyArray(MulticallResponseEventLog)\n\ntype EthBalanceChanges = t.Static\nconst EthBalanceChanges = t.ReadonlyArray(\n\tt.Object({\n\t\taddress: EthereumAddress,\n\t\tbefore: EthereumQuantity,\n\t\tafter: EthereumQuantity,\n\t}).asReadonly()\n)\n\ntype SingleMulticallResponse = t.Static\nconst SingleMulticallResponse = t.Union(\n\tt.Object({\n\t\tstatusCode: t.Literal(1).withParser(LiteralConverterParserFactory(1, 'success' as const)),\n\t\tgasSpent: EthereumQuantity,\n\t\treturnValue: EthereumData,\n\t\tevents: MulticallResponseEventLogs,\n\t\tbalanceChanges: EthBalanceChanges,\n\t}).asReadonly(),\n\tt.Object({\n\t\tstatusCode: t.Literal(0).withParser(LiteralConverterParserFactory(0, 'failure' as const)),\n\t\tgasSpent: EthereumQuantity,\n\t\terror: t.String.withParser(RevertErrorParser),\n\t\treturnValue: EthereumData,\n\t}).asReadonly()\n)\n\nexport type GetSimulationStackReply = t.Static\nexport const GetSimulationStackReply = t.ReadonlyArray(\n\tt.Intersect(\n\t\tEthereumUnsignedTransaction,\n\t\tSingleMulticallResponse,\n\t\tt.Object({\n\t\t\trealizedGasPrice: EthereumQuantity,\n\t\t\tgasLimit: EthereumQuantity,\n\t\t\tmaxPriorityFeePerGas: EthereumQuantity,\n\t\t\tbalanceChanges: EthBalanceChanges\n\t\t}).asReadonly()\n\t)\n)\n"]} \ No newline at end of file diff --git a/docs/js/types/types.d.ts b/docs/js/types/types.d.ts new file mode 100644 index 0000000..1110b01 --- /dev/null +++ b/docs/js/types/types.d.ts @@ -0,0 +1,69 @@ +import { Wallet } from 'ethers'; +import * as t from 'funtypes'; +import { TransactionList } from './bouquetTypes.js'; +export declare function serialize>(funtype: U, value: T): ToWireType; +export type UnionToIntersection = (T extends unknown ? (k: T) => void : never) extends (k: infer I) => void ? I : never; +export type ToWireType = T extends t.Intersect ? UnionToIntersection<{ + [I in keyof U]: ToWireType; +}[number]> : T extends t.Union ? { + [I in keyof U]: ToWireType; +}[number] : T extends t.Record ? Record, ToWireType> : T extends t.Partial ? V extends true ? { + readonly [K in keyof U]?: ToWireType; +} : { + [K in keyof U]?: ToWireType; +} : T extends t.Object ? V extends true ? { + readonly [K in keyof U]: ToWireType; +} : { + [K in keyof U]: ToWireType; +} : T extends t.Readonly> ? { + readonly [P in keyof U]: ToWireType; +} : T extends t.Tuple ? { + [P in keyof U]: ToWireType; +} : T extends t.ReadonlyArray ? readonly ToWireType[] : T extends t.Array ? ToWireType[] : T extends t.ParsedValue ? ToWireType : T extends t.Codec ? U : never; +export type HexString = `0x${string}`; +interface Eip1193Provider { + request(request: { + method: string; + params?: Array | Record; + }): Promise; + on(eventName: string | symbol, listener: (...args: any[]) => void): this; + removeListener(eventName: string | symbol, listener: (...args: any[]) => void): this; +} +declare global { + interface Window { + ethereum?: Eip1193Provider; + } +} +export type BlockInfo = { + blockNumber: bigint; + baseFee: bigint; + priorityFee: bigint; +}; +export type Bundle = { + transactions: TransactionList; + containsFundingTx: boolean; + totalGas: bigint; + inputValue: bigint; + uniqueSigners: string[]; +}; +export type AppSettings = { + blocksInFuture: bigint; + priorityFee: bigint; + simulationRelayEndpoint: string; + submissionRelayEndpoint: string; +}; +export type Signers = { + burner: Wallet | undefined; + burnerBalance: bigint; + bundleSigners: { + [account: string]: Wallet; + }; +}; +export type PromiseState = 'pending' | 'resolved' | 'rejected'; +export type BundleInfo = { + hash: string; + state: PromiseState; + details: string; +}; +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/docs/js/types/types.d.ts.map b/docs/js/types/types.d.ts.map new file mode 100644 index 0000000..2a3a0e8 --- /dev/null +++ b/docs/js/types/types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../ts/types/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/docs/js/types/types.js b/docs/js/types/types.js new file mode 100644 index 0000000..89c67b8 --- /dev/null +++ b/docs/js/types/types.js @@ -0,0 +1,4 @@ +export function serialize(funtype, value) { + return funtype.serialize(value); +} +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/docs/js/types/types.js.map b/docs/js/types/types.js.map new file mode 100644 index 0000000..0dfd5aa --- /dev/null +++ b/docs/js/types/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../ts/types/types.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,SAAS,CAA0B,OAAU,EAAE,KAAQ;IACtE,OAAO,OAAO,CAAC,SAAS,CAAC,KAAK,CAAkB,CAAA;AACjD,CAAC","sourcesContent":["import { Wallet } from 'ethers'\nimport * as t from 'funtypes'\nimport { TransactionList } from './bouquetTypes.js'\n\nexport function serialize>(funtype: U, value: T) {\n\treturn funtype.serialize(value) as ToWireType\n}\n\nexport type UnionToIntersection = (T extends unknown ? (k: T) => void : never) extends (k: infer I) => void ? I : never\n\nexport type ToWireType = T extends t.Intersect\n\t? UnionToIntersection<{ [I in keyof U]: ToWireType }[number]>\n\t: T extends t.Union\n\t? { [I in keyof U]: ToWireType }[number]\n\t: T extends t.Record\n\t? Record, ToWireType>\n\t: T extends t.Partial\n\t? V extends true\n\t? { readonly [K in keyof U]?: ToWireType }\n\t: { [K in keyof U]?: ToWireType }\n\t: T extends t.Object\n\t? V extends true\n\t? { readonly [K in keyof U]: ToWireType }\n\t: { [K in keyof U]: ToWireType }\n\t: T extends t.Readonly>\n\t? { readonly [P in keyof U]: ToWireType }\n\t: T extends t.Tuple\n\t? { [P in keyof U]: ToWireType }\n\t: T extends t.ReadonlyArray\n\t? readonly ToWireType[]\n\t: T extends t.Array\n\t? ToWireType[]\n\t: T extends t.ParsedValue\n\t? ToWireType\n\t: T extends t.Codec\n\t? U\n\t: never\n\nexport type HexString = `0x${string}`\n\ninterface Eip1193Provider {\n\trequest(request: { method: string; params?: Array | Record }): Promise\n\ton(eventName: string | symbol, listener: (...args: any[]) => void): this\n\tremoveListener(eventName: string | symbol, listener: (...args: any[]) => void): this\n}\n\ndeclare global {\n\tinterface Window {\n\t\tethereum?: Eip1193Provider\n\t}\n}\n\nexport type BlockInfo = { blockNumber: bigint; baseFee: bigint; priorityFee: bigint }\nexport type Bundle = { transactions: TransactionList; containsFundingTx: boolean; totalGas: bigint; inputValue: bigint; uniqueSigners: string[] }\nexport type AppSettings = { blocksInFuture: bigint; priorityFee: bigint; simulationRelayEndpoint: string; submissionRelayEndpoint: string }\nexport type Signers = { burner: Wallet | undefined; burnerBalance: bigint; bundleSigners: { [account: string]: Wallet } }\n\nexport type PromiseState = 'pending' | 'resolved' | 'rejected'\nexport type BundleInfo = { hash: string; state: PromiseState; details: string }\n"]} \ No newline at end of file diff --git a/docs/ts/components/App.tsx b/docs/ts/components/App.tsx new file mode 100644 index 0000000..d182f22 --- /dev/null +++ b/docs/ts/components/App.tsx @@ -0,0 +1,41 @@ +import { Import } from './Import.js' +import { Submit } from './Submit.js' +import { Button } from './Button.js' +import { Transactions } from './Transactions.js' +import { connectBrowserProvider } from '../library/provider.js' +import { Navbar } from './Navbar.js' +import { createGlobalState } from '../stores.js' +import { Footer } from './Footer.js' +import { ConfigureKeys } from './ConfigureKeys.js' +import { ConfigureFunding } from './ConfigureFunding.js' + +export function App() { + const state = createGlobalState() + + return ( +
+ +
+ {!state.provider.value && state.bundle.value ? ( +
+

Welcome Back

+ +
+ ) : ( + <> + + {state.bundle.value ? : null} +

2. Configure

+ {state.bundle.value ? (<>) :

No transactions imported yet.

} + + + )} +
+
+
+ ) +} diff --git a/docs/ts/components/Blockie.tsx b/docs/ts/components/Blockie.tsx new file mode 100644 index 0000000..4ae3eae --- /dev/null +++ b/docs/ts/components/Blockie.tsx @@ -0,0 +1,197 @@ +import { JSX } from 'preact/jsx-runtime' +import { ReadonlySignal, Signal, useSignalEffect } from '@preact/signals' +import { useAsyncState } from '../library/asyncState.js' +import { DataURLCache } from '../library/DataURLCache.js' + +const dataURLCache = new DataURLCache() + +class Future implements PromiseLike { + private promise: Promise + private resolveFunction: (value: T | PromiseLike) => void + private rejectFunction: (reason: Error) => void + + constructor() { + let resolveFunction: (value: T | PromiseLike) => void + let rejectFunction: (reason: Error) => void + this.promise = new Promise((resolve: (value: T | PromiseLike) => void, reject: (reason: Error) => void) => { + resolveFunction = resolve + rejectFunction = reject + }) + // the function passed to the Promise constructor is called before the constructor returns, so we can be sure the resolve and reject functions have been set by here even if the compiler can't verify + this.resolveFunction = resolveFunction! + this.rejectFunction = rejectFunction! + } + + public get asPromise() { return this.promise } + + public readonly then = ( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, + onrejected?: ((reason: Error) => TResult2 | PromiseLike) | undefined | null + ): PromiseLike => { + return this.promise.then(onfulfilled, onrejected) + } + + public readonly resolve = (value: T | PromiseLike) => { + this.resolveFunction!(value) + } + + public readonly reject = (reason: Error) => { + this.rejectFunction!(reason) + } +} + +function addressString(address: bigint) { + return `0x${address.toString(16).padStart(40, '0')}` +} + +interface BlockieProps { + address: Signal | ReadonlySignal, + scale?: Signal, + style?: JSX.CSSProperties +} + +function generateIdenticon(address: bigint, scale: number, canvasRef: HTMLCanvasElement) { + // NOTE -- Majority of this code is referenced from: https://github.com/alexvandesande/blockies + // Mostly to ensure congruence to Ethereum Mist's Identicons + + // The random number is a js implementation of the Xorshift PRNG + const randseed = new Array(4) // Xorshift: [x, y, z, w] 32 bit values + + function seedrand(seed: string) { + for (let i = 0; i < randseed.length; i++) { + randseed[i] = 0 + } + for (let i = 0; i < seed.length; i++) { + randseed[i % 4] = ((randseed[i % 4] << 5) - randseed[i % 4]) + seed.charCodeAt(i) + } + } + + function rand() { + // based on Java's String.hashCode(), expanded to 4 32bit values + const t = randseed[0] ^ (randseed[0] << 11) + + randseed[0] = randseed[1] + randseed[1] = randseed[2] + randseed[2] = randseed[3] + randseed[3] = (randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8)) + + return (randseed[3] >>> 0) / ((1 << 31) >>> 0) + } + + function createColor() { + // saturation is the whole color spectrum + const h = Math.floor(rand() * 360) + // saturation goes from 40 to 100, it avoids greyish colors + const s = ((rand() * 60) + 40) + '%' + // lightness can be anything from 0 to 100, but probabilities are a bell curve around 50% + const l = ((rand() + rand() + rand() + rand()) * 25) + '%' + + const color = 'hsl(' + h + ',' + s + ',' + l + ')' + return color + } + + function createImageData(size: number) { + const width = size // Only support square icons for now + const height = size + + const dataWidth = Math.ceil(width / 2) + const mirrorWidth = width - dataWidth + + const data = [] + for (let y = 0; y < height; y++) { + let row = [] + for (let x = 0; x < dataWidth; x++) { + // this makes foreground and background color to have a 43% (1/2.3) probability + // spot color has 13% chance + row[x] = Math.floor(rand() * 2.3) + } + const r = row.slice(0, mirrorWidth) + r.reverse() + row = row.concat(r) + + for (let i = 0; i < row.length; i++) { + data.push(row[i]) + } + } + + return data + } + + function setCanvas(identicon: HTMLCanvasElement, imageData: number[], color: string, scale: number, bgcolor: string, spotcolor: string) { + const width = Math.sqrt(imageData.length) + const size = width * scale + + identicon.width = size + identicon.style.width = `${size}px` + + identicon.height = size + identicon.style.height = `${size}px` + + const cc = identicon.getContext('2d') + cc!.fillStyle = bgcolor + cc!.fillRect(0, 0, identicon.width, identicon.height) + cc!.fillStyle = color + + for (let i = 0; i < imageData.length; i++) { + // if data is 2, choose spot color, if 1 choose foreground + cc!.fillStyle = (imageData[i] === 1) ? color : spotcolor + + // if data is 0, leave the background + if (imageData[i]) { + const row = Math.floor(i / width) + const col = i % width + + cc!.fillRect(col * scale, row * scale, scale, scale) + } + } + } + + const seed = addressString(address) + + seedrand(seed) + + const color = createColor() + const bgcolor = createColor() + const spotcolor = createColor() + const imageData = createImageData(8) + const canvas = setCanvas(canvasRef, imageData, color, scale, bgcolor, spotcolor) + + return canvas +} + +async function renderBlockieToUrl(address: Signal, scale: Signal | undefined) { + const key = `${address.value}!${scale?.value || 4}` + const cacheResult = dataURLCache.get(key) + if (cacheResult !== undefined) return cacheResult + const future = new Future() + const element = document.createElement('canvas') + generateIdenticon(address.value, scale?.value || 4, element) + element.toBlob((blob) => { + if (!blob) return + const dataUrl = URL.createObjectURL(blob) + dataURLCache.set(dataUrl, key) + future.resolve(dataUrl) + }) + return await future +} + +export function Blockie(props: BlockieProps) { + const dimension = 8 * (props.scale?.value || 4) + const { value: dataURL, waitFor } = useAsyncState() + useSignalEffect(() => { + props.address.value + waitFor(async () => renderBlockieToUrl(props.address, props.scale)) + }) + return unknown +}) => { + return ( + + ) +} diff --git a/docs/ts/components/ConfigureFunding.tsx b/docs/ts/components/ConfigureFunding.tsx new file mode 100644 index 0000000..389c310 --- /dev/null +++ b/docs/ts/components/ConfigureFunding.tsx @@ -0,0 +1,219 @@ +import { batch, ReadonlySignal, Signal, useComputed, useSignal, useSignalEffect } from '@preact/signals' +import { EtherSymbol, formatEther, getAddress, JsonRpcProvider, Wallet } from 'ethers' +import { JSX } from 'preact/jsx-runtime' +import { NETWORKS } from '../constants.js' +import { useAsyncState } from '../library/asyncState.js' +import { getMaxBaseFeeInFutureBlock } from '../library/bundleUtils.js' +import { ProviderStore } from '../library/provider.js' +import { addressString } from '../library/utils.js' +import { EthereumAddress } from '../types/ethereumTypes.js' +import { AppSettings, BlockInfo, Bundle, Signers } from '../types/types.js' +import { Button } from './Button.js' +import { SingleNotice } from './Warns.js' + +export const ConfigureFunding = ({ + provider, + appSettings, + bundle, + fundingAmountMin, + signers, + blockInfo, +}: { + provider: Signal + bundle: Signal + signers: Signal + fundingAmountMin: ReadonlySignal + blockInfo: Signal, + appSettings: Signal +}) => { + const signerKeys = useSignal<{ + [address: string]: { input: string; wallet: Wallet | null } + }>({}) + + useSignalEffect(() => { + if (!bundle.value) signerKeys.value = {} + }) + + if (bundle.peek() && Object.keys(signerKeys.peek()).length === 0) { + signerKeys.value = + bundle.value && Object.keys(signerKeys.peek()).length === 0 + ? bundle.value.uniqueSigners.reduce( + ( + curr: { + [address: string]: { input: string; wallet: Wallet | null } + }, + address, + ) => { + curr[getAddress(address)] = { input: '', wallet: null } + return curr + }, + {}, + ) + : {} + } + + blockInfo.subscribe(() => { + if (provider.value && signers.value.burner) { + provider.value.provider.getBalance(signers.value.burner.address).then((balance) => (signers.value.burnerBalance = balance)) + } + }) + + function copyBurnerToClipboard() { + if (!signers.value.burner) return + navigator.clipboard.writeText(signers.value.burner.address) + } + + const showWithdrawModal = useSignal(false) + + function openWithdrawModal() { + showWithdrawModal.value = true + } + + return ( + <> + + {bundle.value && bundle.value.containsFundingTx && signers.value.burner ? ( +
+

Deposit To Funding Account

+

This is a temporary account, send only enough needed plus a tiny bit to account for possible rising gas price changes.

+
+ + +
+

+ Wallet Balance: {EtherSymbol}{formatEther(signers.value.burnerBalance)} +
+ Minimum Required Balance: {EtherSymbol}{formatEther(fundingAmountMin.value)} +

+
+ ) : null} + + ) +} + +const WithdrawModal = ({ display, blockInfo, signers, provider }: { display: Signal, provider: Signal, signers: Signal, blockInfo: Signal }) => { + if (!display.value) return null + + const recipientAddress = useSignal<{ input: string, address?: EthereumAddress }>({ input: '' }) + const inputStyle = useComputed(() => `flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${recipientAddress.value.address ? 'border-green-400' : (recipientAddress.value.input ? 'border-red-400' : 'border-white/50 focus-within:border-white/80')}`) + function parseInput(input: string) { + const address = EthereumAddress.safeParse(input) + recipientAddress.value = { input, address: address.success ? address.value : undefined } + } + + const withdrawAmount = useComputed(() => { + let maxFeePerGas = getMaxBaseFeeInFutureBlock(blockInfo.value.baseFee, 5n) + blockInfo.value.priorityFee; + let fee = maxFeePerGas * 21000n + let amount = signers.value.burnerBalance - fee + return { amount, fee, maxFeePerGas } + }) + + const { value: signedMessage, waitFor } = useAsyncState() + + // Default check if we know the network, can also switch to true if sending to known RPC fails + const useBrowserProvider = useSignal(provider.value && !(provider.value.chainId.toString(10) in NETWORKS) ? true : false) + + const blockExplorer = useComputed(() => { + if (provider.value) { + const chainId = provider.value.chainId.toString(10) + return chainId in NETWORKS ? NETWORKS[chainId].blockExplorer : undefined + } + return undefined + }) + + function withdraw() { + waitFor(async () => { + if (withdrawAmount.value.amount <= 0n) throw 'Funding account\'s balance is to small to withdraw' + if (!signers.value.burner) throw 'No funding account found' + if (!provider.value) throw 'User not connected' + if (!recipientAddress.value.address) throw 'No recipient provided' + + // Worst case scenario, attempt to send via browser wallet if no NETWORK config for chainId or previous error sending to known RPC + if (useBrowserProvider.value === true) { + try { + const burnerWithBrowserProvider = signers.value.burner.connect(provider.value.provider) + const txInput = await burnerWithBrowserProvider.populateTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas }) + const tx = await burnerWithBrowserProvider.signTransaction(txInput) + const txHash = await provider.value.provider.send('eth_sendRawTransaction', [tx]) + return txHash as string + } catch (error) { + throw error + } + } + + // If user is on network that is in NETWORK, send via ethRpc + const chainId = provider.value.chainId.toString(10) + if (!(chainId in NETWORKS)) { + useBrowserProvider.value = true + throw 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.' + } + + const fundingWithProvider = signers.value.burner.connect(new JsonRpcProvider(NETWORKS[chainId].rpcUrl)) + try { + const tx = await fundingWithProvider.sendTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas }) + fundingWithProvider.provider?.destroy() + return tx.hash + } catch (error) { + console.warn('Error sending burner withdraw tx to known RPC:', error) + fundingWithProvider.provider?.destroy() + useBrowserProvider.value = true + throw 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.' + } + }) + } + + function close() { + batch(() => { + display.value = false + recipientAddress.value = { input: '' } + signedMessage.value.state = 'inactive' + }) + } + + return ( +
+
e.stopPropagation()}> +

Withdraw From Funding Account

+
+ ETH Recipient + ) => parseInput(e.currentTarget.value)} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='0x...' /> +
+ {withdrawAmount.value.amount > 0n + ? (

Withdraw {EtherSymbol} {formatEther(withdrawAmount.value.amount)} + {EtherSymbol} {formatEther(withdrawAmount.value.fee)} fee

) + : (

Transfer fee ({EtherSymbol} {formatEther(withdrawAmount.value.fee)}) is more than funding account balance

)} +
+ +
+

{signedMessage.value.state === 'rejected' ? : ''}

+

{signedMessage.value.state === 'resolved' ? Transaction submitted with TX Hash {signedMessage.value.value} : Transaction submitted with TX Hash {signedMessage.value.value}} title='Transaction Submitted' /> : ''}

+
+
+ ) +} + diff --git a/docs/ts/components/ConfigureKeys.tsx b/docs/ts/components/ConfigureKeys.tsx new file mode 100644 index 0000000..4eaeffa --- /dev/null +++ b/docs/ts/components/ConfigureKeys.tsx @@ -0,0 +1,88 @@ +import { batch, Signal, useSignal, useSignalEffect } from '@preact/signals' +import { Wallet } from 'ethers' +import { JSX } from 'preact/jsx-runtime' +import { ProviderStore } from '../library/provider.js' +import { BlockInfo, Bundle, Signers } from '../types/types.js' + +export const ConfigureKeys = ({ + provider, + bundle, + signers, + blockInfo, +}: { + provider: Signal + bundle: Signal + signers: Signal + blockInfo: Signal +}) => { + const signerKeys = useSignal<{ + [address: string]: { input: string; wallet: Wallet | null } + }>({}) + + useSignalEffect(() => { + if (!bundle.value) signerKeys.value = {} + if (bundle.value && bundle.value.uniqueSigners.join() !== Object.keys(signerKeys.value).join()) { + signerKeys.value = bundle.value.uniqueSigners.reduce(( + curr: { + [address: string]: { input: string; wallet: Wallet | null } + }, + address, + ) => { + curr[address] = { input: '', wallet: null } + return curr + }, + {}, + ) + } + }) + + blockInfo.subscribe(() => { + if (provider.value && signers.value.burner) { + provider.value.provider.getBalance(signers.value.burner.address).then((balance) => (signers.value.burnerBalance = balance)) + } + }) + + function tryUpdateSigners(address: string, privateKey: string) { + batch(() => { + try { + const wallet = new Wallet(privateKey) + + signerKeys.value = { + ...signerKeys.peek(), + [address]: { + wallet: wallet.address === address ? wallet : null, + input: privateKey, + }, + } + } catch { + signerKeys.value = { + ...signerKeys.peek(), + [address]: { wallet: null, input: privateKey }, + } + } + if (Object.values(signerKeys.value).filter(({ wallet }) => !wallet).length === 0) { + signers.value = { + ...signers.peek(), + bundleSigners: Object.values(signerKeys.peek()).reduce((acc: { [account: string]: Wallet }, wallet) => { + if (wallet.wallet) { + acc[wallet.wallet.address] = wallet.wallet + } + return acc + }, {}), + } + } + }) + } + + return ( +
+

Enter Private Keys For Signing Accounts

+ {Object.keys(signerKeys.value).map((address) => ( +
+ {address} + ) => tryUpdateSigners(address, e.currentTarget.value)} value={signerKeys.value[address].input} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder={`Enter private key for account`} /> +
+ ))} +
+ ) +} diff --git a/docs/ts/components/Footer.tsx b/docs/ts/components/Footer.tsx new file mode 100644 index 0000000..4ddf032 --- /dev/null +++ b/docs/ts/components/Footer.tsx @@ -0,0 +1,19 @@ +export const Footer = () => ( + +) diff --git a/docs/ts/components/Import.tsx b/docs/ts/components/Import.tsx new file mode 100644 index 0000000..f6cd440 --- /dev/null +++ b/docs/ts/components/Import.tsx @@ -0,0 +1,170 @@ +import { batch, Signal, useSignal } from '@preact/signals' +import { useState } from 'preact/hooks' +import { parseEther } from 'ethers' +import { connectBrowserProvider, ProviderStore } from '../library/provider.js' +import { GetSimulationStackReply } from '../types/interceptorTypes.js' +import { Button } from './Button.js' +import { AppSettings, Bundle, serialize, Signers } from '../types/types.js' +import { EthereumAddress } from '../types/ethereumTypes.js' +import { TransactionList } from '../types/bouquetTypes.js' +import { ImportModal } from './ImportModal.js' +import { SingleNotice } from './Warns.js' +import { addressString } from '../library/utils.js' + +export async function importFromInterceptor( + bundle: Signal, + provider: Signal, + blockInfo: Signal<{ + blockNumber: bigint + baseFee: bigint + priorityFee: bigint + }>, + appSettings: Signal, + signers: Signal | undefined, +) { + if (!window.ethereum || !window.ethereum.request) throw Error('No Ethereum wallet detected') + connectBrowserProvider(provider, blockInfo, signers, appSettings) + + const { payload } = await window.ethereum + .request({ + method: 'interceptor_getSimulationStack', + params: ['1.0.0'], + }) + .catch((err: { code: number }) => { + if (err?.code === -32601) { + throw new Error('Wallet does not support returning simulations') + } else { + throw new Error(`Unknown Error: ${JSON.stringify(err)}`) + } + }) + + const tryParse = GetSimulationStackReply.safeParse(payload) + if (!tryParse.success) throw new Error('Wallet does not support returning simulations') + if (tryParse.value.length === 0) throw new Error('You have no transactions on your simulation') + + const converted = TransactionList.safeParse(serialize(GetSimulationStackReply, tryParse.value).map(({ from, to, value, input, gasLimit, chainId }) => ({ from, to, value, input, gasLimit, chainId }))) + if (!converted.success) throw new Error('Malformed simulation stack') + + if (converted.value.length >= 2 && converted.value[0].to === converted.value[1].from && converted.value[0].value === parseEther('200000')) { + const fundingAddr = converted.value[0].from + converted.value = converted.value.map(tx => tx.from === fundingAddr ? { ...tx, from: 'FUNDING' } : tx) + } + + const uniqueToAddresses = [...new Set(converted.value.map(({ from }) => from))] + const containsFundingTx = uniqueToAddresses.includes('FUNDING') + const uniqueSigners = uniqueToAddresses.filter((address): address is EthereumAddress => address !== 'FUNDING').map(address => addressString(address)) + + const totalGas = converted.value.reduce((sum, tx) => tx.gasLimit + sum, 0n) + + // Take addresses that recieved funding, determine spend deficit - gas fees + const fundingRecipients = new Set(converted.value.reduce((result: bigint[], tx) => (tx.to && tx.from === 'FUNDING' ? [...result, tx.to] : result), [])) + + const spenderDeficits = tryParse.value.reduce((amounts: { [account: string]: { deficit: bigint, credit: bigint } }, tx) => { + if (!fundingRecipients.has(tx.from)) return amounts + const receipientBalanceChanges = tx.balanceChanges.filter(x => x.address === tx.from) + + const consumed = tx.value + // Rebate is the difference between balance change and consume amount (if there were any internal transactions sending ETH back), ignore gas fees + const balanceChange = receipientBalanceChanges.reduce((result: bigint, balanceChange) => result + balanceChange.after - balanceChange.before, 0n) + const rebate = balanceChange + consumed + tx.maxPriorityFeePerGas * tx.gasSpent + + // Calcuate current deficit + if (tx.from.toString() in amounts) { + // If credit, deduct current credit from new consumption, or cancel out new consumption and open credit - whichever is smaller + if (amounts[tx.from.toString()].credit > 0n) { + if (amounts[tx.from.toString()].credit <= consumed) { + amounts[tx.from.toString()].deficit += consumed - amounts[tx.from.toString()].credit + amounts[tx.from.toString()].credit = rebate + } else { + // If consumed less than current rebates, deficit does not increase. + amounts[tx.from.toString()].credit += rebate - consumed + } + } + } else { + amounts[tx.from.toString()] = { deficit: consumed, credit: rebate } + } + return amounts + + }, {}) + + const inputValue = Object.values(spenderDeficits).reduce((sum, spender) => spender.deficit + sum, 0n) + + // Copy value and set, input of funding to inputValue + const transactions = [...converted.value] + if (containsFundingTx) { + transactions[0] = { ...transactions[0], value: inputValue } + } + + localStorage.setItem('payload', JSON.stringify(TransactionList.serialize(transactions))) + bundle.value = { transactions, containsFundingTx, uniqueSigners, totalGas, inputValue } +} + +export const Import = ({ + bundle, + provider, + blockInfo, + signers, + appSettings, +}: { + bundle: Signal + provider: Signal + blockInfo: Signal<{ + blockNumber: bigint + baseFee: bigint + priorityFee: bigint + }> + signers: Signal + appSettings: Signal +}) => { + const showImportModal = useSignal(false) + const [error, setError] = useState(undefined) + + const clearPayload = () => { + batch(() => { + bundle.value = undefined + localStorage.removeItem('payload') + signers.value.bundleSigners = {} + setError('') + // Keep burner wallet as long as it has funds, should clear is later if there is left over dust but not needed. + // if (fundingAccountBalance.value === 0n) signers.value.burner = undefined + }) + } + + return ( + <> + {showImportModal.value ? setError('')} display={showImportModal} /> : null} +

1. Import

+
+
+ + + {bundle.value ? ( + + ) : null} +
+ {error ? : null} + {error && error === 'Wallet does not support returning simulations' ? ( +

+ Don't have The Interceptor Installed? Install it here{' '} + + here + + . +

+ ) : ( + '' + )} +
+ + ) + } diff --git a/docs/ts/components/ImportModal.tsx b/docs/ts/components/ImportModal.tsx new file mode 100644 index 0000000..75d83a3 --- /dev/null +++ b/docs/ts/components/ImportModal.tsx @@ -0,0 +1,82 @@ +import { Signal, useComputed, useSignal } from '@preact/signals' +import { JSX } from 'preact/jsx-runtime' +import { addressString } from '../library/utils.js' +import { TransactionList } from '../types/bouquetTypes.js' +import { EthereumAddress } from '../types/ethereumTypes.js' +import { Bundle } from '../types/types.js' +import { Button } from './Button.js' + +const placeholder = `[ + { + "from": "0xb3cd36cfaa07652dbfecca76f438ff8998a4f539", + "to": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "value": "0x16345785d8a0000", + "input": "0xd0e30db0", + "chainId": "0x1", + "gasLimit": "0x15f90" + }, + { + "from": "0xb3cd36cfaa07652dbfecca76f438ff8998a4f539", + "to": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "value": "0x0", + "input": "0x2e1a7d4d000000000000000000000000000000000000000000000000016345785d8a0000", + "chainId": "0x1", + "gasLimit": "0x15f90" + } +]` + +export const ImportModal = ({ display, bundle, clearError }: { display: Signal, clearError: () => void, bundle: Signal }) => { + const jsonInput = useSignal('') + + const isValid = useComputed(() => { + if (!jsonInput.value) return false + try { + const { success } = TransactionList.safeParse(JSON.parse(jsonInput.value)) + return success + } catch { + return false + } + }) + + function importJson() { + if (!isValid.peek()) return + const txList = TransactionList.parse(JSON.parse(jsonInput.value)) + + localStorage.setItem('payload', JSON.stringify(TransactionList.serialize(txList))) + + const uniqueToAddresses = [...new Set(txList.map(({ from }) => from))] + const containsFundingTx = uniqueToAddresses.includes('FUNDING') + const uniqueSigners = uniqueToAddresses.filter((address): address is EthereumAddress => address !== 'FUNDING').map(address => addressString(address)) + + const totalGas = txList.reduce((sum, tx) => tx.gasLimit + sum, 0n) + const inputValue = txList.reduce((sum, tx) => (tx.from === 'FUNDING' ? tx.value : 0n) + sum, 0n) + + bundle.value = { transactions: txList, containsFundingTx, uniqueSigners, totalGas, inputValue } + clearError() + close() + } + + function close() { + jsonInput.value = '' + display.value = false + } + return display.value ? ( +
+
e.stopPropagation()}> +

Import Transactions From JSON

+
+