-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocs.json
More file actions
1 lines (1 loc) · 76 KB
/
Copy pathdocs.json
File metadata and controls
1 lines (1 loc) · 76 KB
1
[{"name":"Web3","comment":" Top-level module that composes wallet and transaction state.\n\nThis module bundles `Web3.Wallet.State` and a list of named `Web3.Transaction.Status`\nvalues into a single `Model`. Wire it into your app's model/update/subscriptions\nto get wallet connection, chain validation, and transaction tracking with a single\nport pair.\n\n port web3Cmd : Json.Encode.Value -> Cmd msg\n port web3Sub : (Json.Decode.Value -> msg) -> Sub msg\n\n type alias Model =\n { web3 : Web3.Model\n , ...\n }\n\n type Msg\n = Web3Msg Web3.Msg\n | ...\n\n init : ( Model, Cmd Msg )\n init =\n ( { web3 = Web3.init (Web3.Types.chainId 369), ... }, Cmd.none )\n\n update msg model =\n case msg of\n Web3Msg subMsg ->\n ( { model | web3 = Web3.update subMsg model.web3 }, Cmd.none )\n\n subscriptions model =\n web3Sub (Json.Decode.decodeValue Web3.Wallet.decoder\n >> Result.map Web3.WalletMsg\n >> Result.withDefault (Web3Msg (Web3.WalletMsg Web3.Wallet.WalletDisconnected))\n )\n\nFor individual modules without the combined wrapper, import `Web3.Wallet`,\n`Web3.Transaction`, `Web3.Balance`, `Web3.Block`, etc. directly.\n\n@docs Model, Msg\n@docs init, update, subscriptions, encodeTxCmd\n\n","unions":[{"name":"Msg","comment":" Messages for wallet and transaction updates.\n","args":[],"cases":[["WalletMsg",["Web3.Wallet.Msg"]],["TxMsg",["String.String","Web3.Transaction.Msg"]],["TxCmdMsg",["String.String","Web3.Transaction.TxCmd"]]]}],"aliases":[{"name":"Model","comment":" Combined wallet + transaction state.\n","args":[],"type":"{ wallet : Web3.Wallet.State, expectedChain : Web3.Types.ChainId, transactions : List.List ( String.String, Web3.Transaction.Status ) }"}],"values":[{"name":"encodeTxCmd","comment":" Encode a `TxCmd` (e.g. `RequestReceipt`) for sending via your port.\n\n web3Cmd (Web3.encodeTxCmd (Tx.RequestReceipt hash \"my-id\"))\n\n","type":"Web3.Transaction.TxCmd -> Json.Encode.Value"},{"name":"init","comment":" Initialize with the expected chain ID.\n","type":"Web3.Types.ChainId -> Web3.Model"},{"name":"subscriptions","comment":" Placeholder for port subscriptions. Wire your port decoder here.\n","type":"Web3.Model -> Platform.Sub.Sub Web3.Msg"},{"name":"update","comment":" Update wallet and transaction state from a port message.\n","type":"Web3.Msg -> Web3.Model -> Web3.Model"}],"binops":[]},{"name":"Web3.Abi.Calldata","comment":" Pure-Elm ABI calldata encoding for contract calls.\n\nProduces the exact hex bytes that go on the wire — selector + ABI-encoded\nparameters — without any JavaScript surface. The result of\n[`calldata`](#calldata) is a `\"0x…\"` string suitable for the `data` field\nof `eth_call` / `eth_sendTransaction`.\n\nThe encoder follows the Solidity ABI specification's \"head/tail\" layout:\n\n - **Static types** (`address`, `uintN`, `intN`, `bool`, `bytesN` for `N ≤ 32`)\n occupy 32 bytes inline in the head section.\n - **Dynamic types** (`string`, `bytes`, `T[]`, tuples containing any dynamic\n field) occupy 32 bytes in the head holding the **offset** of their data\n within the calldata, with the actual content appended to the tail\n (length-prefixed for variable-length types).\n\nCodegen tools should *bake the 4-byte selector at codegen time* (computed via\nkeccak256 of the function signature) and pass it to [`calldata`](#calldata).\nThat keeps the runtime entirely in Elm — no JS hash function needed.\n\n -- balanceOf(address) — selector is keccak256(\"balanceOf(address)\")[:4] = 70a08231\n calldata \"70a08231\" [ address holder ]\n == \"0x70a08231000000000000000000000000abcd…\"\n\n -- approve(address,uint256)\n calldata \"095ea7b3\"\n [ address spender\n , uint256 amount\n ]\n\n -- transferBatch(address[], uint256[]) — dynamic\n calldata \"deadbeef\"\n [ list address recipients\n , list uint256 amounts\n ]\n\n@docs Slot\n@docs address, uint256, uintN, int256, bool, bytes32, bytesN\n@docs string, bytes\n@docs list, tuple\n@docs calldata\n\n","unions":[{"name":"Slot","comment":" A piece of an ABI parameter list — either a static 32-byte chunk or a\ndynamic blob that lives in the tail.\n\nThe internals are deliberately opaque: callers construct `Slot`s via the\ntyped helpers below and never inspect the hex themselves.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"address","comment":" 20-byte address, left-padded to 32 bytes. ","type":"Web3.Types.Address -> Web3.Abi.Calldata.Slot"},{"name":"bool","comment":" `bool`, encoded as a 32-byte slot of zeros (false) or zeros + `01` (true).\n","type":"Basics.Bool -> Web3.Abi.Calldata.Slot"},{"name":"bytes","comment":" Raw bytes (`bytes`), accepted as `\"0x…\"` or bare hex. Encoded as a\nlength-prefixed dynamic blob.\n","type":"String.String -> Web3.Abi.Calldata.Slot"},{"name":"bytes32","comment":" `bytes32` — 32 bytes of arbitrary data, accepting either `\"0x…\"` or bare\nhex. Right-padded with zeros if shorter than 32 bytes.\n","type":"String.String -> Web3.Abi.Calldata.Slot"},{"name":"bytesN","comment":" `bytesN` for `N ∈ {1..32}`. Right-padded to 32 bytes.\n\n bytesN 4 \"0xdeadbeef\"\n --> 0xdeadbeef00000000…00 (32 bytes total)\n\n","type":"Basics.Int -> String.String -> Web3.Abi.Calldata.Slot"},{"name":"calldata","comment":" Combine a 4-byte selector and a list of [`Slot`](#Slot)s into the full\ncalldata hex string.\n\nThe selector is **bare hex** (no `\"0x\"` prefix), exactly 8 characters\n(4 bytes). Codegen tools should compute this at codegen time via\n`keccak256(signature).slice(0, 8)` and bake it as a constant — this module\nintentionally does not include a keccak implementation, so it stays pure\ndata layout.\n\n calldata \"70a08231\" [ address holder ]\n --> \"0x70a08231000000…<holder padded to 32 bytes>\"\n\n","type":"String.String -> List.List Web3.Abi.Calldata.Slot -> String.String"},{"name":"int256","comment":" Signed 256-bit integer, encoded as two's-complement, left-padded to 32\nbytes.\n\n int256 (BigInt.fromInt -1)\n --> 0xffffffff…ffff (32 bytes of 0xff)\n\n","type":"Web3.BigInt.BigInt -> Web3.Abi.Calldata.Slot"},{"name":"list","comment":" Dynamic array `T[]`, encoded as `length || encode(elements)`. ","type":"(a -> Web3.Abi.Calldata.Slot) -> List.List a -> Web3.Abi.Calldata.Slot"},{"name":"string","comment":" UTF-8 string, encoded as a length-prefixed dynamic blob.\n","type":"String.String -> Web3.Abi.Calldata.Slot"},{"name":"tuple","comment":" Tuple (struct), encoded inline if every component is static, or as a\ndynamic blob otherwise.\n\nThe wire layout matches Solidity's: a tuple of all-static fields occupies the\nsum of its components' slots inline; a tuple containing any dynamic field is\nitself dynamic and lives in the tail with the inner layout recursed.\n","type":"List.List Web3.Abi.Calldata.Slot -> Web3.Abi.Calldata.Slot"},{"name":"uint256","comment":" Unsigned 256-bit integer, left-padded to 32 bytes.\n\nNegative values are encoded as their absolute value; for signed integers use\n[`int256`](#int256) instead.\n","type":"Web3.BigInt.BigInt -> Web3.Abi.Calldata.Slot"},{"name":"uintN","comment":" Unsigned integer of `n` bits (8/16/24/.../256), encoded identically to\n[`uint256`](#uint256). Width is a hint to callers; on the wire all unsigned\nintegers up to 256 bits occupy one 32-byte slot.\n\nBounds-checking is the caller's responsibility — a value exceeding `2^n - 1`\nis encoded as `uint256` and will revert on-chain in `solc 0.8+`.\n","type":"Basics.Int -> Web3.BigInt.BigInt -> Web3.Abi.Calldata.Slot"}],"binops":[]},{"name":"Web3.Abi.Decode","comment":" Helpers to decode contract return values from JSON\nreceived through ports from the JS Web3 layer.\n\n@docs address, uint256, int256, bool, string, bytes32\n@docs uint8, uint16, uint32, uint64, uint128\n@docs hexSlot, uint256Slot, addressSlot, boolSlot, stringSlot, listSlot\n@docs tuple2Hex, tuple3Hex\n@docs decodeRevertReason, decodeCustomError\n\n","unions":[],"aliases":[],"values":[{"name":"address","comment":" Decode an Address return value.\n","type":"Json.Decode.Decoder Web3.Types.Address"},{"name":"addressSlot","comment":" Decode an Address from slot `n` of a raw 0x-hex ABI response.\nAddresses are right-aligned in the 32-byte slot.\n","type":"Basics.Int -> String.String -> Maybe.Maybe Web3.Types.Address"},{"name":"bool","comment":" Decode a bool return value.\n","type":"Json.Decode.Decoder Basics.Bool"},{"name":"boolSlot","comment":" Decode a bool from slot `n` of a raw 0x-hex ABI response.\n","type":"Basics.Int -> String.String -> Maybe.Maybe Basics.Bool"},{"name":"bytes32","comment":" Decode a bytes32 hex string (e.g. an event topic). Expects a 0x-prefixed\n66-character hex string and returns it as-is.\n","type":"Json.Decode.Decoder String.String"},{"name":"decodeCustomError","comment":" Decode a typed Solidity custom error (`error InsufficientBalance(uint256\nhave, uint256 want)`) from raw revert data, given selector fragments the app\nbakes at codegen time — the same no-runtime-keccak philosophy as\n`Web3.Abi.Calldata` selectors.\n\n fragments =\n [ { selector = \"cf479181\" -- keccak(\"InsufficientBalance(uint256,uint256)\")[:4]\n , name = \"InsufficientBalance\"\n , decodeArgs = \\tail -> Maybe.map2 (\\a b -> [ a, b ])\n (word 0 tail) (word 1 tail)\n }\n ]\n\n decodeCustomError fragments revertData\n --> Just { name = \"InsufficientBalance\", args = [ \"5\", \"10\" ] }\n\n`decodeArgs` receives the ABI-encoded argument tail as bare hex (no `0x`,\nselector already stripped) and renders each argument to a display string —\nbuild it from this module's slot readers.\n\nPrecedence, decided: this function REFUSES the standard selectors\n`08c379a0` (`Error(string)`) and `4e487b71` (`Panic(uint256)`) so it\ncomposes with [`decodeRevertReason`](#decodeRevertReason) unambiguously in\neither order — each decoder has a disjoint domain.\n\nReturns `Nothing` for: standard selectors, unknown selectors, payloads\nshorter than a selector, or a fragment whose `decodeArgs` fails.\n\n","type":"List.List { selector : String.String, name : String.String, decodeArgs : String.String -> Maybe.Maybe (List.List String.String) } -> String.String -> Maybe.Maybe { name : String.String, args : List.List String.String }"},{"name":"decodeRevertReason","comment":" Attempt to decode an EVM revert reason from raw revert data.\n\nChecks for the Error(string) selector `0x08c379a0` and decodes the\nABI-encoded string that follows. Returns Nothing if the data is not\na standard Error(string) revert.\n\n decodeRevertReason \"0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000011496e73756666696369656e742066756e647300000000000000000000000000\"\n --> Just \"Insufficient funds\"\n\n","type":"String.String -> Maybe.Maybe String.String"},{"name":"hexSlot","comment":" Extract the 64-character hex of the 32-byte word at slot index `n`\n(0-indexed) from a 0x-prefixed ABI-encoded hex string.\n\n hexSlot 0 \"0x0000...0064\" == \"0000...0064\"\n\n","type":"Basics.Int -> String.String -> String.String"},{"name":"int256","comment":" Decode an int256 return value as a BigInt.\n","type":"Json.Decode.Decoder Web3.BigInt.BigInt"},{"name":"listSlot","comment":" Decode a dynamic array from slot `n`. Each element is decoded by calling\n`elemDecoder slotIndex fullHex`. Works for static-element arrays (uint256[],\naddress[], etc.) where elements are stored consecutively.\n","type":"Basics.Int -> (Basics.Int -> String.String -> Maybe.Maybe a) -> String.String -> Maybe.Maybe (List.List a)"},{"name":"string","comment":" Decode a string return value.\n","type":"Json.Decode.Decoder String.String"},{"name":"stringSlot","comment":" Decode a dynamic UTF-8 string from slot `n` of a raw 0x-hex ABI response.\nSlot `n` contains an offset pointer; the string length and data follow at\nthat offset.\n","type":"Basics.Int -> String.String -> Maybe.Maybe String.String"},{"name":"tuple2Hex","comment":" Decode a static 2-tuple from the head of a 0x-hex ABI response.\nEach decoder is called with its slot index (0, 1).\n","type":"(Basics.Int -> String.String -> Maybe.Maybe a) -> (Basics.Int -> String.String -> Maybe.Maybe b) -> String.String -> Maybe.Maybe ( a, b )"},{"name":"tuple3Hex","comment":" Decode a static 3-tuple from the head of a 0x-hex ABI response.\n","type":"(Basics.Int -> String.String -> Maybe.Maybe a) -> (Basics.Int -> String.String -> Maybe.Maybe b) -> (Basics.Int -> String.String -> Maybe.Maybe c) -> String.String -> Maybe.Maybe ( a, b, c )"},{"name":"uint128","comment":" Decode a uint128 return value as a BigInt.\n","type":"Json.Decode.Decoder Web3.BigInt.BigInt"},{"name":"uint16","comment":" Decode a uint16 return value as an Elm Int (validated 0–65535).\n","type":"Json.Decode.Decoder Basics.Int"},{"name":"uint256","comment":" Decode a uint256 return value as a BigInt.\nAccepts both decimal strings (\"100\") and 0x-prefixed hex strings (\"0x64\").\n","type":"Json.Decode.Decoder Web3.BigInt.BigInt"},{"name":"uint256Slot","comment":" Decode a uint256 from slot `n` of a raw 0x-hex ABI response.\n","type":"Basics.Int -> String.String -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"uint32","comment":" Decode a uint32 return value as an Elm Int (validated 0–4294967295).\n","type":"Json.Decode.Decoder Basics.Int"},{"name":"uint64","comment":" Decode a uint64 return value as a BigInt (exceeds JS/Elm safe Int range).\n","type":"Json.Decode.Decoder Web3.BigInt.BigInt"},{"name":"uint8","comment":" Decode a uint8 return value as an Elm Int (validated 0–255).\n","type":"Json.Decode.Decoder Basics.Int"}],"binops":[]},{"name":"Web3.Abi.Encode","comment":" Helpers to encode contract call parameters to JSON values\nfor passing through ports to the JS Web3 layer.\n\n@docs address, uint256, int256, bool, string, bytes, bytes32, bytesN\n@docs list, tuple2, tuple3\n\n","unions":[],"aliases":[],"values":[{"name":"address","comment":" Encode an Address argument.\n","type":"Web3.Types.Address -> Json.Encode.Value"},{"name":"bool","comment":" Encode a bool argument.\n","type":"Basics.Bool -> Json.Encode.Value"},{"name":"bytes","comment":" Encode raw bytes as a hex string.\n","type":"String.String -> Json.Encode.Value"},{"name":"bytes32","comment":" Encode a bytes32 value.\n","type":"String.String -> Json.Encode.Value"},{"name":"bytesN","comment":" Encode a bytesN value (bytes1 through bytes31).\n","type":"String.String -> Json.Encode.Value"},{"name":"int256","comment":" Encode an int256 argument from a BigInt.\n","type":"Web3.BigInt.BigInt -> Json.Encode.Value"},{"name":"list","comment":" Encode a dynamic array argument.\n\n -- Transfer(address[],uint256[])\n Encode.list Encode.address recipients\n Encode.list Encode.uint256 amounts\n\n","type":"(a -> Json.Encode.Value) -> List.List a -> Json.Encode.Value"},{"name":"string","comment":" Encode a string argument.\n","type":"String.String -> Json.Encode.Value"},{"name":"tuple2","comment":" Encode a 2-tuple (struct with two fields).\n\n -- swap(address token, uint256 amount)\n Encode.tuple2 Encode.address Encode.uint256 ( tokenAddr, amount )\n\n","type":"(a -> Json.Encode.Value) -> (b -> Json.Encode.Value) -> ( a, b ) -> Json.Encode.Value"},{"name":"tuple3","comment":" Encode a 3-tuple (struct with three fields).\n","type":"(a -> Json.Encode.Value) -> (b -> Json.Encode.Value) -> (c -> Json.Encode.Value) -> ( a, b, c ) -> Json.Encode.Value"},{"name":"uint256","comment":" Encode a uint256 argument from a BigInt.\n","type":"Web3.BigInt.BigInt -> Json.Encode.Value"}],"binops":[]},{"name":"Web3.Balance","comment":" Typed balance query with correlation IDs.\n\nThis module provides a dedicated, typed interface for querying native ETH/PLS\nbalances. Multiple queries can be in flight simultaneously — each carries a\ncorrelation `id` that is echoed back so responses can be matched.\n\n -- Send via your port:\n web3Cmd (Web3.Balance.encode (Web3.Balance.getBalance address \"my-id\"))\n\n -- Receive via your port:\n case D.decodeValue Web3.Balance.decoder incoming of\n Ok (Web3.Balance.GotBalance id wei) ->\n -- id matches the one you sent; wei is the amount\n Err _ ->\n -- not a balance response\n\n@docs Cmd, Msg\n@docs getBalance, encode, decoder\n\n","unions":[{"name":"Cmd","comment":" A pending balance request. Carry the address and a correlation id.\n","args":[],"cases":[]},{"name":"Msg","comment":" A resolved balance response. Contains the correlation id and the amount in wei.\n","args":[],"cases":[["GotBalance",["String.String","Web3.Types.Wei"]]]}],"aliases":[],"values":[{"name":"decoder","comment":" Decode a `{tag:'balance', id, wei}` response from the JS port.\n","type":"Json.Decode.Decoder Web3.Balance.Msg"},{"name":"encode","comment":" Encode a `Cmd` for the JS port.\n\nProduces `{tag:'getBalance', address, id}`.\n\n","type":"Web3.Balance.Cmd -> Json.Encode.Value"},{"name":"getBalance","comment":" Build a balance query for `address`, tagged with `id`.\n","type":"Web3.Types.Address -> String.String -> Web3.Balance.Cmd"}],"binops":[]},{"name":"Web3.BigInt","comment":" Arbitrary-precision integers for EVM applications.\n\nSupports the full uint256 range (0 to 2^256-1) and int256 range.\nImplemented as a base-10^7 digit list with no external dependencies.\n\nAll values crossing the port boundary are decimal strings — this module\nhandles the conversion safely.\n\n@docs BigInt\n@docs fromInt, fromString, fromIntString, fromHexString, toString, toHexString\n@docs add, sub, mul, div, mod\n@docs compare, eq, lt, lte, gt, gte\n@docs zero, isZero\n@docs decoder\n\n","unions":[{"name":"BigInt","comment":" An arbitrary-precision integer.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"add","comment":" Add two BigInts.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Web3.BigInt.BigInt"},{"name":"compare","comment":" Compare two BigInts.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Basics.Order"},{"name":"decoder","comment":" Decode a BigInt from a JSON decimal string.\n\n D.decodeString BigInt.decoder \"\\\"12345\\\"\" == Ok (BigInt.fromInt 12345)\n\n","type":"Json.Decode.Decoder Web3.BigInt.BigInt"},{"name":"div","comment":" Divide. Returns Nothing if divisor is zero.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"eq","comment":" Equality.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Basics.Bool"},{"name":"fromHexString","comment":" Parse a 0x-prefixed hexadecimal string as a non-negative BigInt.\nReturns Nothing for invalid input or empty hex body.\n\n fromHexString \"0x64\" == Just (fromInt 100)\n fromHexString \"0xFF\" == Just (fromInt 255)\n fromHexString \"0x\" == Nothing\n fromHexString \"0xgg\" == Nothing\n\n","type":"String.String -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"fromInt","comment":" Create a BigInt from an Elm Int.\n","type":"Basics.Int -> Web3.BigInt.BigInt"},{"name":"fromIntString","comment":" Alias for fromString (decimal). Kept for API symmetry with fromHexString.\n","type":"String.String -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"fromString","comment":" Parse a decimal integer string. Returns Nothing for invalid input.\n\nAccepts optional leading '-' or '+' sign. Rejects empty strings,\nnon-digit characters, and floating-point notation.\n\n fromString \"0\" == Just zero\n fromString \"-42\" == Just (fromInt -42)\n fromString \"115792...9935\" -- uint256 max: Just <big>\n fromString \"abc\" == Nothing\n fromString \"\" == Nothing\n\n","type":"String.String -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"gt","comment":" Greater than.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Basics.Bool"},{"name":"gte","comment":" Greater than or equal.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Basics.Bool"},{"name":"isZero","comment":" Is this BigInt zero?\n","type":"Web3.BigInt.BigInt -> Basics.Bool"},{"name":"lt","comment":" Less than.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Basics.Bool"},{"name":"lte","comment":" Less than or equal.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Basics.Bool"},{"name":"mod","comment":" Remainder: a `mod` b. Returns Nothing if b is zero.\n\n mod (fromInt 10) (fromInt 3) == Just (fromInt 1)\n mod (fromInt 10) zero == Nothing\n\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"mul","comment":" Multiply.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Web3.BigInt.BigInt"},{"name":"sub","comment":" Subtract.\n","type":"Web3.BigInt.BigInt -> Web3.BigInt.BigInt -> Web3.BigInt.BigInt"},{"name":"toHexString","comment":" Convert a non-negative `BigInt` to a lower-case hexadecimal string\n**without** a `\"0x\"` prefix or leading zeros.\n\nReturns `\"0\"` for zero. For negative integers, the sign is dropped and the\nabsolute value is rendered — callers needing two's-complement should do the\ntwiddling themselves (or use `Web3.Abi.Calldata.int256`).\n\n toHexString (fromInt 0) == \"0\"\n toHexString (fromInt 255) == \"ff\"\n toHexString (fromInt 65535) == \"ffff\"\n\n","type":"Web3.BigInt.BigInt -> String.String"},{"name":"toString","comment":" Convert to decimal string.\n","type":"Web3.BigInt.BigInt -> String.String"},{"name":"zero","comment":" Zero.\n","type":"Web3.BigInt.BigInt"}],"binops":[]},{"name":"Web3.Block","comment":" Block number and block data queries.\n\n -- One-shot block number query:\n port web3Cmd : Json.Encode.Value -> Cmd msg\n port web3Sub : (Json.Decode.Value -> msg) -> Sub msg\n\n type Msg = GotBlock Block.Msg | ...\n\n subscriptions model =\n web3Sub (Json.Decode.decodeValue Block.decoder >> Result.toMaybe >> Maybe.map GotBlock)\n\n fetchBlock : Platform.Cmd msg\n fetchBlock =\n web3Cmd (Block.encode (Block.getBlockNumber \"my-id\"))\n\n@docs Cmd, Msg, Block\n@docs getBlockNumber, getBlock, watchBlockNumber, getBlockTransactionCount\n@docs encode, decoder\n@docs unwatchBlockNumber\n\n","unions":[{"name":"Cmd","comment":" Commands to query block data via port.\n","args":[],"cases":[["RequestBlockNumber",["String.String"]],["RequestBlock",["Web3.Types.BlockNumber","String.String"]],["WatchBlockNumber",["String.String"]],["RequestBlockTxCount",["Web3.Types.BlockNumber","String.String"]]]},{"name":"Msg","comment":" Messages from the JS block port.\n","args":[],"cases":[["GotBlockNumber",["String.String","Basics.Int"]],["GotBlock",["String.String","Web3.Block.Block"]],["GotBlockTxCount",["String.String","Basics.Int"]]]}],"aliases":[{"name":"Block","comment":" A block header with key fields.\n","args":[],"type":"{ number : Basics.Int, hash : String.String, timestamp : Basics.Int, gasLimit : Web3.BigInt.BigInt, gasUsed : Web3.BigInt.BigInt, baseFeePerGas : Maybe.Maybe Web3.BigInt.BigInt, parentHash : String.String }"}],"values":[{"name":"decoder","comment":" Decode Msg responses from the JS port.\n","type":"Json.Decode.Decoder Web3.Block.Msg"},{"name":"encode","comment":" Encode a Cmd for the JS port.\n","type":"Web3.Block.Cmd -> Json.Encode.Value"},{"name":"getBlock","comment":" Request a specific block by block number. The `id` is echoed back.\n","type":"Web3.Types.BlockNumber -> String.String -> Web3.Block.Cmd"},{"name":"getBlockNumber","comment":" Request the current block number. The `id` is echoed back in the response.\n","type":"String.String -> Web3.Block.Cmd"},{"name":"getBlockTransactionCount","comment":" Request the number of transactions in a block. The second argument is a request ID.\n","type":"Web3.Types.BlockNumber -> String.String -> Web3.Block.Cmd"},{"name":"unwatchBlockNumber","comment":" Stop a block-number watcher started with [`watchBlockNumber`](#watchBlockNumber).\nThe `id` must match the one passed to `watchBlockNumber`. Clears the JS-side\npolling interval and/or the WebSocket `newHeads` subscription.\n\n web3Cmd (Block.unwatchBlockNumber \"block-watch\")\n\nThis is a standalone encoder producing the port value directly — it is\ndeliberately NOT a new variant of [`Cmd`](#Cmd), because adding a variant\nto an exposed custom type is a MAJOR change under Elm's enforced semver\n(consumer `case` expressions over `Cmd` would stop compiling). A\nstandalone function keeps this addition MINOR-safe.\n\n","type":"String.String -> Json.Encode.Value"},{"name":"watchBlockNumber","comment":" Start polling the block number every 4 seconds. The `id` tags each\nGotBlockNumber response so you can distinguish multiple watchers.\n","type":"String.String -> Web3.Block.Cmd"}],"binops":[]},{"name":"Web3.Chain","comment":" Chain definitions for EVM networks.\n\nEach `Chain` bundles the chain ID, name, default RPC URL, block explorer URL,\nand native currency symbol. Pass `Chain.chainId someChain` wherever a\n`Web3.Types.ChainId` is needed (e.g. `Wallet.update` and `Wallet.switchChain`).\n\n import Web3.Chain as Chain\n import Web3.Wallet as Wallet\n\n expectedChain : Web3.Types.ChainId\n expectedChain =\n Chain.chainId Chain.pulsechain\n\n -- Add a network to the wallet (EIP-3085):\n addPulseChain : Web3.Wallet.WalletCmd\n addPulseChain =\n Wallet.addChain\n { chainId = 369\n , chainName = Chain.name Chain.pulsechain\n , rpcUrls = [ Chain.rpcUrl Chain.pulsechain ]\n , nativeCurrency = { name = \"Pulse\", symbol = \"PLS\", decimals = 18 }\n , blockExplorerUrls = [ Chain.blockExplorer Chain.pulsechain ]\n }\n\n@docs Chain\n@docs pulsechain, pulsechainTestnet, ethereum, sepolia\n@docs bsc, polygon, arbitrum, optimism, base, avalanche, zksync, fantom, gnosis, linea, scroll\n@docs custom\n@docs chainId, name, rpcUrl, blockExplorer\n\n","unions":[],"aliases":[{"name":"Chain","comment":" An EVM chain definition.\n","args":[],"type":"{ chainId : Web3.Types.ChainId, name : String.String, rpcUrl : String.String, blockExplorer : String.String, nativeCurrency : String.String }"}],"values":[{"name":"arbitrum","comment":" Arbitrum One (chain ID 42161).\n","type":"Web3.Chain.Chain"},{"name":"avalanche","comment":" Avalanche C-Chain (chain ID 43114).\n","type":"Web3.Chain.Chain"},{"name":"base","comment":" Base mainnet (chain ID 8453).\n","type":"Web3.Chain.Chain"},{"name":"blockExplorer","comment":" Get the block explorer URL.\n","type":"Web3.Chain.Chain -> String.String"},{"name":"bsc","comment":" BNB Smart Chain mainnet (chain ID 56).\n","type":"Web3.Chain.Chain"},{"name":"chainId","comment":" Get the chain ID.\n","type":"Web3.Chain.Chain -> Web3.Types.ChainId"},{"name":"custom","comment":" Define a custom EVM chain.\n","type":"{ chainId : Basics.Int, name : String.String, rpcUrl : String.String, blockExplorer : String.String, nativeCurrency : String.String } -> Web3.Chain.Chain"},{"name":"ethereum","comment":" Ethereum mainnet (chain ID 1).\n","type":"Web3.Chain.Chain"},{"name":"fantom","comment":" Fantom Opera (chain ID 250).\n","type":"Web3.Chain.Chain"},{"name":"gnosis","comment":" Gnosis Chain (chain ID 100).\n","type":"Web3.Chain.Chain"},{"name":"linea","comment":" Linea mainnet (chain ID 59144).\n","type":"Web3.Chain.Chain"},{"name":"name","comment":" Get the chain name.\n","type":"Web3.Chain.Chain -> String.String"},{"name":"optimism","comment":" Optimism (chain ID 10).\n","type":"Web3.Chain.Chain"},{"name":"polygon","comment":" Polygon PoS mainnet (chain ID 137).\n","type":"Web3.Chain.Chain"},{"name":"pulsechain","comment":" PulseChain mainnet (chain ID 369).\n\nThe block explorer URL points to scan.pulsechain.com served via Pinata's IPFS\ngateway. This is the proper decentralised access method — the same explorer,\nbut fetched from IPFS rather than a centralised host.\n\n","type":"Web3.Chain.Chain"},{"name":"pulsechainTestnet","comment":" PulseChain testnet v4 (chain ID 943).\n","type":"Web3.Chain.Chain"},{"name":"rpcUrl","comment":" Get the RPC URL.\n","type":"Web3.Chain.Chain -> String.String"},{"name":"scroll","comment":" Scroll mainnet (chain ID 534352).\n","type":"Web3.Chain.Chain"},{"name":"sepolia","comment":" Sepolia testnet (chain ID 11155111).\n","type":"Web3.Chain.Chain"},{"name":"zksync","comment":" zkSync Era mainnet (chain ID 324).\n","type":"Web3.Chain.Chain"}],"binops":[]},{"name":"Web3.Contract.Call","comment":" Type-safe contract read calls (eth\\_call).\n\nBuild a read call, encode it for the JS port, decode the response.\nThe return type is parameterized so your decoder is checked at compile time.\n\n import Web3.Contract.Call as Call\n import Web3.Abi.Decode as Decode\n import Web3.Abi.Encode as Encode\n\n -- Read a uint256 return value\n totalSupply : T.Address -> Call.ReadCall BigInt\n totalSupply token =\n Call.readCall\n { contract = token\n , method = \"totalSupply()\"\n , args = []\n , decoder = Decode.uint256\n , id = \"total-supply\"\n }\n\n -- Simulate a write to catch reverts before broadcasting\n simulate : T.Address -> BigInt -> T.Address -> Call.ReadCall Bool\n simulate router amount caller =\n Call.readCall\n { contract = router\n , method = \"buy(uint256)\"\n , args = [ Encode.uint256 amount ]\n , decoder = Decode.bool\n , id = \"sim-buy\"\n }\n |> Call.withFrom caller\n\n -- Send via port\n web3Cmd (Call.encode (totalSupply tokenAddress))\n\n -- Decode response\n result = D.decodeValue (Call.responseDecoder myCall) incoming\n\nRelated modules: `Web3.Multicall` for batching multiple reads into one RPC call;\n`Web3.Contract.Send` for write calls.\n\n@docs ReadCall\n@docs readCall, readCallRaw, withBlock, withFrom, encode, responseDecoder\n\n","unions":[{"name":"ReadCall","comment":" A read-only contract call with a typed return value.\n","args":["a"],"cases":[]}],"aliases":[],"values":[{"name":"encode","comment":" Encode a read call for the JS port.\n","type":"Web3.Contract.Call.ReadCall a -> Json.Encode.Value"},{"name":"readCall","comment":" Create a read call. The `id` is echoed back in the response so you can\nmatch responses to requests when multiple calls are in flight.\n","type":"{ contract : Web3.Types.Address, method : String.String, args : List.List Json.Encode.Value, decoder : Json.Decode.Decoder a, id : String.String } -> Web3.Contract.Call.ReadCall a"},{"name":"readCallRaw","comment":" Create a read call from **pre-built hex calldata** — the result of\n[`Web3.Abi.Calldata.calldata`](Web3-Abi-Calldata#calldata). The JS port\nbridge sends `data` directly without re-encoding, so the wire path is\nentirely pure-Elm: no method-name string, no arg encoding outside of Elm.\n\n -- balanceOf(address) — selector baked at codegen time\n balanceOf : T.Address -> T.Address -> ReadCall BigInt\n balanceOf contract holder =\n readCallRaw\n { contract = contract\n , data = Calldata.calldata \"70a08231\" [ Calldata.address holder ]\n , decoder = AbiDecode.uint256\n , id = \"balanceOf\"\n }\n\nThe `data` argument must be a complete `\"0x…\"` calldata string including the\n4-byte function selector.\n","type":"{ contract : Web3.Types.Address, data : String.String, decoder : Json.Decode.Decoder a, id : String.String } -> Web3.Contract.Call.ReadCall a"},{"name":"responseDecoder","comment":" Get the response decoder for a read call.\n","type":"Web3.Contract.Call.ReadCall a -> Json.Decode.Decoder a"},{"name":"withBlock","comment":" Set the block number for the call.\n","type":"Web3.Types.BlockNumber -> Web3.Contract.Call.ReadCall a -> Web3.Contract.Call.ReadCall a"},{"name":"withFrom","comment":" Add a `from` address — turns eth\\_call into a simulation of a write.\nCatches reverts without broadcasting.\n\n simulateBuy tokenAddress amount userAddress\n |> withFrom userAddress\n |> encode\n |> web3Cmd\n\n","type":"Web3.Types.Address -> Web3.Contract.Call.ReadCall a -> Web3.Contract.Call.ReadCall a"}],"binops":[]},{"name":"Web3.Contract.Event","comment":" Contract event watching via port subscriptions.\n\n -- Subscribe to Transfer events\n subscriptions model =\n Event.watchEvent\n { contract = tokenAddress\n , event = \"Transfer\"\n , filter = []\n }\n |> Event.decoder transferDecoder\n |> onContractEvent TransferReceived\n\n@docs EventFilter, EventLog, GetLogsQuery\n@docs watchEvent, encode, decoder\n@docs getLogs, logsDecoder\n\n","unions":[],"aliases":[{"name":"EventFilter","comment":" An event subscription filter.\n","args":[],"type":"{ contract : Web3.Types.Address, event : String.String, topics : List.List (Maybe.Maybe String.String) }"},{"name":"EventLog","comment":" A decoded event log.\n","args":["a"],"type":"{ data : a, contract : Web3.Types.Address, topics : List.List String.String, blockNumber : Basics.Int, txHash : Web3.Types.TxHash, logIndex : Basics.Int }"},{"name":"GetLogsQuery","comment":" A query for getLogs with fromBlock/toBlock range.\n","args":[],"type":"{ contract : Web3.Types.Address, fromBlock : Web3.Types.BlockNumber, toBlock : Web3.Types.BlockNumber, topics : List.List (Maybe.Maybe String.String) }"}],"values":[{"name":"decoder","comment":" Decode a `watchEvent` log from the JS port.\n\nRequires the message to have `tag: \"eventLog\"` — use `logsDecoder` for\nthe batch `getLogs` response which wraps logs in an array.\n\n","type":"Json.Decode.Decoder a -> Json.Decode.Decoder (Web3.Contract.Event.EventLog a)"},{"name":"encode","comment":" Encode an event filter for the JS port.\n","type":"Web3.Contract.Event.EventFilter -> Json.Encode.Value"},{"name":"getLogs","comment":" Encode a getLogs query for the JS port.\n","type":"Web3.Contract.Event.GetLogsQuery -> Json.Encode.Value"},{"name":"logsDecoder","comment":" Decode a list of event logs with a custom data decoder.\n\nDecodes the `{ tag: \"logs\", logs: [...] }` response from `getLogs`.\n\n","type":"Json.Decode.Decoder a -> Json.Decode.Decoder (List.List (Web3.Contract.Event.EventLog a))"},{"name":"watchEvent","comment":" Create an event watch command.\n","type":"Web3.Contract.Event.EventFilter -> Json.Encode.Value"}],"binops":[]},{"name":"Web3.Contract.Send","comment":" Type-safe contract write calls (eth\\_sendTransaction).\n\nBuild a write call, encode it for the JS port, optionally estimate gas first.\n\n -- Non-payable: approve\n approve : Address -> BigInt -> WriteCall\n approve spender amount =\n writeCall\n { contract = tokenAddress\n , method = \"approve\"\n , args = [ Encode.address spender, Encode.uint256 amount ]\n }\n\n -- Payable: buy\n buy : BigInt -> Wei -> WriteCall\n buy minTokens value =\n payableCall\n { contract = routerAddress\n , method = \"buy\"\n , args = [ Encode.uint256 minTokens ]\n , value = value\n }\n\n@docs WriteCall\n@docs writeCall, writeCallRaw, payableCall, payableCallRaw, withGasLimit\n@docs encode, estimateGas, deployCall, encodeRawSend\n\n","unions":[{"name":"WriteCall","comment":" A write call to a contract.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"deployCall","comment":" Encode a contract deployment for submission via the port. ","type":"{ bytecode : String.String, args : List.List Json.Encode.Value, gasLimit : Maybe.Maybe Basics.Int } -> Json.Encode.Value"},{"name":"encode","comment":" Encode a write call for the JS port.\n","type":"Web3.Contract.Send.WriteCall -> Json.Encode.Value"},{"name":"encodeRawSend","comment":" Encode a raw signed transaction for broadcast via the port. ","type":"String.String -> Json.Encode.Value"},{"name":"estimateGas","comment":" Encode a write call as an estimateGas command for the JS port.\n\n estimateGas myWriteCall\n -- sends { tag: \"estimateGas\", contract: ..., method: ..., args: ..., value: ... }\n -- JS responds with { tag: \"gasEstimate\", gas: \"21000\" }\n\n","type":"Web3.Contract.Send.WriteCall -> Json.Encode.Value"},{"name":"payableCall","comment":" Create a payable write call with a value.\n","type":"{ contract : Web3.Types.Address, method : String.String, args : List.List Json.Encode.Value, value : Web3.BigInt.BigInt } -> Web3.Contract.Send.WriteCall"},{"name":"payableCallRaw","comment":" Create a payable write call from pre-built hex calldata + a value.\n","type":"{ contract : Web3.Types.Address, data : String.String, value : Web3.BigInt.BigInt } -> Web3.Contract.Send.WriteCall"},{"name":"withGasLimit","comment":" Set a gas limit.\n","type":"Basics.Int -> Web3.Contract.Send.WriteCall -> Web3.Contract.Send.WriteCall"},{"name":"writeCall","comment":" Create a non-payable write call.\n","type":"{ contract : Web3.Types.Address, method : String.String, args : List.List Json.Encode.Value } -> Web3.Contract.Send.WriteCall"},{"name":"writeCallRaw","comment":" Create a write call from pre-built hex calldata — the result of\n[`Web3.Abi.Calldata.calldata`](Web3-Abi-Calldata#calldata). The JS port\nbridge sends `data` directly without re-encoding.\n\n approve : T.Address -> T.Address -> BigInt -> WriteCall\n approve contract spender amount =\n writeCallRaw\n { contract = contract\n , data =\n Calldata.calldata \"095ea7b3\"\n [ Calldata.address spender\n , Calldata.uint256 amount\n ]\n }\n\n","type":"{ contract : Web3.Types.Address, data : String.String } -> Web3.Contract.Send.WriteCall"}],"binops":[]},{"name":"Web3.Crypto","comment":" Cryptographic utilities via the Web3 port.\n\n@docs Cmd, Msg, keccak256, encode, decoder\n","unions":[{"name":"Cmd","comment":" Commands for the Crypto port. ","args":[],"cases":[]},{"name":"Msg","comment":" Messages from the Crypto port. ","args":[],"cases":[["GotKeccak256",["String.String","String.String"]]]}],"aliases":[],"values":[{"name":"decoder","comment":" Decode a Crypto message received from the port. ","type":"Json.Decode.Decoder Web3.Crypto.Msg"},{"name":"encode","comment":" Encode a Crypto command to send through the port. ","type":"Web3.Crypto.Cmd -> Json.Encode.Value"},{"name":"keccak256","comment":" Request the keccak256 hash of a UTF-8 string. The second argument is a request ID. ","type":"String.String -> String.String -> Web3.Crypto.Cmd"}],"binops":[]},{"name":"Web3.Fee","comment":" Gas price and fee history queries.\n\n fetchGasPrice : Platform.Cmd msg\n fetchGasPrice =\n web3Cmd (Fee.encode (Fee.getGasPrice \"gas-query\"))\n\n@docs Cmd, Msg, FeeHistory\n@docs getGasPrice, getFeeHistory\n@docs encode, decoder\n@docs getMaxPriorityFee, maxPriorityFeeDecoder\n\n","unions":[{"name":"Cmd","comment":" Commands to query fee data via port.\n","args":[],"cases":[["RequestGasPrice",["String.String"]],["RequestFeeHistory",["String.String","Basics.Int"]]]},{"name":"Msg","comment":" Messages from the JS fee port.\n","args":[],"cases":[["GotGasPrice",["String.String","Web3.BigInt.BigInt"]],["GotFeeHistory",["String.String","Web3.Fee.FeeHistory"]]]}],"aliases":[{"name":"FeeHistory","comment":" Historical fee data from eth_feeHistory.\n","args":[],"type":"{ baseFeePerGas : List.List Web3.BigInt.BigInt, gasUsedRatio : List.List Basics.Float, oldestBlock : Basics.Int }"}],"values":[{"name":"decoder","comment":" Decode Msg responses from the JS port.\n","type":"Json.Decode.Decoder Web3.Fee.Msg"},{"name":"encode","comment":" Encode a Cmd for the JS port.\n","type":"Web3.Fee.Cmd -> Json.Encode.Value"},{"name":"getFeeHistory","comment":" Request fee history for the last `blockCount` blocks.\n","type":"String.String -> Basics.Int -> Web3.Fee.Cmd"},{"name":"getGasPrice","comment":" Request the current gas price (eth_gasPrice). The `id` is echoed back.\n","type":"String.String -> Web3.Fee.Cmd"},{"name":"getMaxPriorityFee","comment":" Request the current max priority fee per gas (`eth_maxPriorityFeePerGas`).\nThe `id` is echoed back in the `maxPriorityFee` response.\n\n web3Cmd (Fee.getMaxPriorityFee \"priority-1\")\n\nThis is a standalone encoder that produces the port value directly — it is\ndeliberately NOT a new variant of [`Cmd`](#Cmd). Adding a variant to an\nexposed custom type is a MAJOR change under Elm's enforced semver (every\n`case` expression over `Cmd` or `Msg` in consumer code would stop\ncompiling), so this addition ships as a pair of standalone functions to\nstay MINOR-safe. Decode the response with\n[`maxPriorityFeeDecoder`](#maxPriorityFeeDecoder).\n\n","type":"String.String -> Json.Encode.Value"},{"name":"maxPriorityFeeDecoder","comment":" Decode the `maxPriorityFee` response from the JS port into\n`( id, wei )`.\n\nStandalone (not a [`Msg`](#Msg) variant) for the same additive-safety\nreason as [`getMaxPriorityFee`](#getMaxPriorityFee): extending `Msg`\nwould be a MAJOR version bump.\n\n case D.decodeValue Fee.maxPriorityFeeDecoder incoming of\n Ok ( id, wei ) ->\n -- wei : BigInt — suggested maxPriorityFeePerGas\n Err _ ->\n -- not a maxPriorityFee response\n\n","type":"Json.Decode.Decoder ( String.String, Web3.BigInt.BigInt )"}],"binops":[]},{"name":"Web3.Multicall","comment":" Batch multiple contract reads into a single eth\\_call via Multicall3.\n\nThe Multicall3 contract (0xcA11bde05977b3631167028862bE2a173976CA11) is\ndeployed on Ethereum, PulseChain, and most EVM networks. It lets you pack N\nread calls into one RPC round-trip.\n\n import Web3.Multicall as Multicall\n import Web3.Abi.Encode as Encode\n\n let\n req =\n Multicall.batch \"balance-check\"\n [ Multicall.callSpec tokenAddress \"balanceOf(address)\" [ Encode.address myAddr ]\n , Multicall.callSpec tokenAddress \"totalSupply()\" []\n ]\n in\n -- Outgoing port: web3Cmd (Multicall.encode req)\n -- Incoming port: match on { tag = \"multicallResult\" } and apply responseDecoder\n\n@docs CallSpec, callSpec, MulticallRequest, CallResult\n@docs batch, encode, responseDecoder\n\n","unions":[{"name":"CallSpec","comment":" A single call specification for inclusion in a multicall batch.\n","args":[],"cases":[]},{"name":"MulticallRequest","comment":" A batched multicall request with a correlation id.\n","args":[],"cases":[]}],"aliases":[{"name":"CallResult","comment":" The result of a single call within a multicall batch.\n\n`data` is the raw ABI-encoded return value as a hex string (0x-prefixed).\nApply your specific decoder (e.g. from Web3.Abi.Decode) to parse it.\n\n","args":[],"type":"{ success : Basics.Bool, data : String.String }"}],"values":[{"name":"batch","comment":" Batch a list of call specs into a multicall request.\n\nThe `id` is echoed back in the `multicallResult` response so you can match\nresponses to requests when multiple batches are in flight.\n\n","type":"String.String -> List.List Web3.Multicall.CallSpec -> Web3.Multicall.MulticallRequest"},{"name":"callSpec","comment":" Build a CallSpec for a contract read.\n\n Multicall.callSpec\n pairAddress\n \"getReserves()\"\n []\n\n","type":"Web3.Types.Address -> String.String -> List.List Json.Encode.Value -> Web3.Multicall.CallSpec"},{"name":"encode","comment":" Encode a multicall request for the JS port.\n\nProduces:\n\n { \"tag\": \"multicall\"\n , \"id\": \"...\"\n , \"calls\": [ { \"contract\": \"0x...\", \"method\": \"...\", \"args\": [...] }, ... ]\n }\n\n","type":"Web3.Multicall.MulticallRequest -> Json.Encode.Value"},{"name":"responseDecoder","comment":" Decoder for the `multicallResult` port response.\n\nExpects:\n\n { \"tag\": \"multicallResult\"\n , \"id\": \"...\"\n , \"results\": [ { \"success\": true, \"data\": \"0x...\" }, ... ]\n }\n\nResults are in the same order as the original call specs.\n\n","type":"Json.Decode.Decoder (List.List Web3.Multicall.CallResult)"}],"binops":[]},{"name":"Web3.Query","comment":" Typed decoders for on-chain read queries: transaction count (nonce),\nstorage slot reads, contract bytecode, and transaction lookup by hash.\n\nEach query carries a correlation `id` that is echoed back so responses can\nbe matched when multiple queries are in flight.\n\n -- Send via your port:\n web3Cmd (Web3.Query.encode (Web3.Query.getTxCount address \"nonce-1\"))\n\n -- Receive via your port:\n case D.decodeValue Web3.Query.decoder incoming of\n Ok (Web3.Query.GotTxCount id nonce) -> ...\n Ok (Web3.Query.GotStorageAt id val) -> ...\n Ok (Web3.Query.GotCode id bytecode) -> ...\n Ok (Web3.Query.GotTransaction id info) -> ...\n Ok (Web3.Query.TransactionNotFound id) -> ...\n Err _ -> -- not a query response\n\n@docs Cmd, Msg, TransactionInfo\n@docs getTxCount, getStorageAt, getCode, getTransaction, encode, decoder\n\n","unions":[{"name":"Cmd","comment":" Commands to send to the JS query port.\n","args":[],"cases":[["RequestTxCount",["Web3.Types.Address","String.String"]],["RequestStorageAt",["Web3.Types.Address","Basics.Int","String.String"]],["RequestCode",["Web3.Types.Address","String.String"]],["RequestTransaction",["Web3.Types.TxHash","String.String"]]]},{"name":"Msg","comment":" Messages from the JS query port.\n","args":[],"cases":[["GotTxCount",["String.String","Basics.Int"]],["GotStorageAt",["String.String","String.String"]],["GotCode",["String.String","String.String"]],["GotTransaction",["String.String","Web3.Query.TransactionInfo"]],["TransactionNotFound",["String.String"]]]}],"aliases":[{"name":"TransactionInfo","comment":" Information about a transaction fetched by hash.\n","args":[],"type":"{ hash : Web3.Types.TxHash, from : Web3.Types.Address, to : Maybe.Maybe Web3.Types.Address, value : Web3.Types.Wei, nonce : Basics.Int, data : String.String, gas : Basics.Int, blockNumber : Maybe.Maybe Basics.Int, blockHash : Maybe.Maybe String.String }"}],"values":[{"name":"decoder","comment":" Decode query responses from the JS port.\n\nHandles `txCount`, `storageAt`, `code`, `transaction`, and `transactionNotFound` tags.\nReturns `Err` for unknown tags.\n\n","type":"Json.Decode.Decoder Web3.Query.Msg"},{"name":"encode","comment":" Encode a `Cmd` for the JS port.\n","type":"Web3.Query.Cmd -> Json.Encode.Value"},{"name":"getCode","comment":" Build a contract bytecode query for `contract`, tagged with `id`.\n","type":"Web3.Types.Address -> String.String -> Web3.Query.Cmd"},{"name":"getStorageAt","comment":" Build a storage slot query. `slot` is the integer slot index (converted to hex).\n","type":"Web3.Types.Address -> Basics.Int -> String.String -> Web3.Query.Cmd"},{"name":"getTransaction","comment":" Request a transaction by hash. The second argument is a request ID.\n","type":"Web3.Types.TxHash -> String.String -> Web3.Query.Cmd"},{"name":"getTxCount","comment":" Build a transaction count (nonce) query for `address`, tagged with `id`.\n","type":"Web3.Types.Address -> String.String -> Web3.Query.Cmd"}],"binops":[]},{"name":"Web3.Sign","comment":" EIP-712 typed data signing and EIP-191 personal signing.\n\nBuild a typed data request, encode it for the JS port, decode the signature response.\nUse the `SignState` machine to track the lifecycle of a single sign request.\n\n import Dict\n import Json.Encode as E\n import Web3.Sign as Sign\n\n permitRequest : T.Address -> T.Address -> BigInt -> Int -> Sign.TypedData\n permitRequest owner spender value nonce =\n Sign.typedData\n { domain =\n { name = Just \"MyToken\", version = Just \"1\"\n , chainId = Just 369, verifyingContract = Just tokenAddress\n , salt = Nothing\n }\n , types =\n Dict.fromList\n [ ( \"Permit\"\n , [ { name = \"owner\", typeName = \"address\" }\n , { name = \"spender\", typeName = \"address\" }\n , { name = \"value\", typeName = \"uint256\" }\n , { name = \"nonce\", typeName = \"uint256\" }\n , { name = \"deadline\", typeName = \"uint256\" }\n ]\n )\n ]\n , primaryType = \"Permit\"\n , message = E.object [ ... ]\n }\n\n -- Send via port:\n web3Cmd (Sign.encode \"permit-1\" signerAddress (permitRequest owner spender value nonce))\n\n -- Receive via port (use signatureDecoder for the raw sig string):\n case D.decodeValue Sign.signatureDecoder incoming of\n Ok sig -> -- sig is the 0x-prefixed signature\n Err _ -> -- not a sign response\n\n**Sign state machine** — tracks one in-flight request:\n\n type SignState\n = SignIdle\n | SignPending String -- id\n | Signed String String -- id, signature\n | SignFailed String String -- id, error\n | SignRejected String -- id\n\n -- Usage:\n ( { model | signState = Sign.startSign \"permit-1\" model.signState }\n , web3Cmd (Sign.encode \"permit-1\" addr request)\n )\n\n -- On port response:\n newSignState = Sign.signUpdate signMsg model.signState\n\n@docs TypedData, Domain, TypeField\n@docs typedData, encode, personalSign, signatureDecoder\n@docs SignState, SignMsg\n@docs startSign, signUpdate, isSignTerminal\n@docs verify, recoveredDecoder\n\n","unions":[{"name":"SignMsg","comment":" Messages from the JS sign port.\n","args":[],"cases":[["SignResponse",["String.String","String.String"]],["SignError",["String.String","String.String"]],["SignCancel",["String.String"]]]},{"name":"SignState","comment":" Signing state machine. Tracks the lifecycle of a single sign request.\n\n - `SignIdle` — no sign request in progress\n - `SignPending id` — awaiting user approval for request `id`\n - `Signed id sig` — user approved; `sig` is the 0x-prefixed signature\n - `SignFailed id err` — signing failed (wallet error, network error)\n - `SignRejected id` — user explicitly cancelled in wallet UI\n\n","args":[],"cases":[["SignIdle",[]],["SignPending",["String.String"]],["Signed",["String.String","String.String"]],["SignFailed",["String.String","String.String"]],["SignRejected",["String.String"]]]},{"name":"TypedData","comment":" An EIP-712 typed data signing request.\n","args":[],"cases":[]}],"aliases":[{"name":"Domain","comment":" EIP-712 domain separator parameters. All fields are optional;\ninclude only those your contract's domain hash covers.\n","args":[],"type":"{ name : Maybe.Maybe String.String, version : Maybe.Maybe String.String, chainId : Maybe.Maybe Basics.Int, verifyingContract : Maybe.Maybe Web3.Types.Address, salt : Maybe.Maybe String.String }"},{"name":"TypeField","comment":" A single field in a struct type definition.\n","args":[],"type":"{ name : String.String, typeName : String.String }"}],"values":[{"name":"encode","comment":" Encode a TypedData request as a port command.\n\n web3Cmd (Sign.encode \"my-id\" signerAddress request)\n\nThe `id` is echoed back in the `signed` response so you can match\nresponses to requests when multiple signing requests are in flight.\n\n","type":"String.String -> Web3.Types.Address -> Web3.Sign.TypedData -> Json.Encode.Value"},{"name":"isSignTerminal","comment":" True if the sign state is terminal (no more updates expected).\n","type":"Web3.Sign.SignState -> Basics.Bool"},{"name":"personalSign","comment":" Sign an arbitrary message with `personal_sign` (EIP-191).\n\nUsed for login flows and simple off-chain authentication. The wallet\nwill display the raw message to the user before signing.\n\n web3Cmd (Sign.personalSign \"login-1\" signerAddress \"Sign in to MyDapp\")\n\nResponses arrive on the same `signed` tag as EIP-712 — use `signatureDecoder`.\n\n","type":"String.String -> Web3.Types.Address -> String.String -> Json.Encode.Value"},{"name":"recoveredDecoder","comment":" Decode the `recovered` response from a [`verify`](#verify) request.\n\n case D.decodeValue Sign.recoveredDecoder incoming of\n Ok { id, address } ->\n -- address : String — the 0x-prefixed recovered signer\n Err _ ->\n -- not a recovered response\n\nStandalone (not a `SignMsg` variant) for the same additive-safety reason\nas [`verify`](#verify).\n\n","type":"Json.Decode.Decoder { id : String.String, address : String.String }"},{"name":"signUpdate","comment":" Update sign state from a port message.\nTerminal states never transition out.\n","type":"Web3.Sign.SignMsg -> Web3.Sign.SignState -> Web3.Sign.SignState"},{"name":"signatureDecoder","comment":" Decode the `signed` response from the JS port.\n\n case D.decodeValue Sign.signatureDecoder incoming of\n Ok sig ->\n -- sig : String — the 0x-prefixed signature\n Err _ ->\n -- handle decode error\n\n","type":"Json.Decode.Decoder String.String"},{"name":"startSign","comment":" Transition from `SignIdle` to `SignPending` for the given correlation id.\nAll other states are unchanged (a sign already in flight is not replaced).\n","type":"String.String -> Web3.Sign.SignState -> Web3.Sign.SignState"},{"name":"typedData","comment":" Construct a TypedData value.\n","type":"{ domain : Web3.Sign.Domain, types : Dict.Dict String.String (List.List Web3.Sign.TypeField), primaryType : String.String, message : Json.Encode.Value } -> Web3.Sign.TypedData"},{"name":"verify","comment":" Verify an EIP-191 `personal_sign` signature by recovering the signer\naddress (`personal_ecRecover`).\n\n web3Cmd\n (Sign.verify\n { id = \"login-verify-1\"\n , message = \"Sign in to MyDapp\"\n , signature = sig\n }\n )\n\nThe recovered address arrives on the `recovered` tag — decode it with\n[`recoveredDecoder`](#recoveredDecoder) and compare it against the address\nthat claims to have signed. Failures arrive on the standard `failed` tag.\n\nThis is a standalone encoder returning the port value directly (like\n[`personalSign`](#personalSign)) rather than a new `Cmd`/`Msg` variant —\nextending an exposed custom type is a MAJOR change under Elm's enforced\nsemver, so additive functions keep this MINOR-safe.\n\n","type":"{ id : String.String, message : String.String, signature : String.String } -> Json.Encode.Value"}],"binops":[]},{"name":"Web3.Subscription","comment":" Push-based event subscriptions over `eth_subscribe`.\n\nThe dominant pattern for reactive dapps. Where [`Web3.Contract.Event`](Web3-Contract-Event)\nfetches historical logs via `eth_getLogs`, this module opens a long-lived\nWebSocket subscription so every NEW log is pushed to your update fn the\nmoment it lands on-chain — no polling, no missed blocks.\n\n\n# The subscription identifier\n\nSubscriptions are tagged with an opaque [`SubscriptionId`](#SubscriptionId)\nso multiple subscriptions can coexist. Pass the same id to\n[`close`](#close) to stop a subscription, and match incoming\n[`LogEvent`](#LogEvent)s against it to route updates.\n\n@docs SubscriptionId, subscriptionId, subscriptionIdToString\n\n\n# Building a logs filter\n\nSubscriptions are built with a tiny pipeline: start with [`logs`](#logs),\nnarrow with [`atAddress`](#atAddress), [`withTopic`](#withTopic), or\n[`withTopics`](#withTopics):\n\n factoryEvents : SubscriptionId -> Cmd msg\n factoryEvents sid =\n Subscription.logs\n |> Subscription.atAddress factoryAddress\n |> Subscription.withTopic 0 tokenCreatedTopicHash\n |> Subscription.open sid\n\n@docs LogFilter, logs, atAddress, withTopic, withTopics\n\n\n# Reading events back\n\n@docs LogEvent, Status\n\n\n# Wire format\n\nThe Cmd helpers below encode a port payload for [`elm-web3-ports.js`](https://github.com/intrepidshape/elm-web3/blob/main/js/elm-web3-ports.js)\nto consume. Pair them with the decoders to interpret incoming subscription\nevents.\n\n@docs open, close, statusDecoder, eventDecoder\n\n","unions":[{"name":"LogFilter","comment":" Opaque, fluent builder for an `eth_subscribe(\"logs\", ...)` filter.\n","args":[],"cases":[]},{"name":"Status","comment":" The high-level lifecycle of a subscription. Surfaced via\n[`statusDecoder`](#statusDecoder) so you can show \"connecting…\" /\n\"reconnecting…\" indicators.\n\n - `Opening` — handshake in progress, no events yet.\n - `Open` — chain push is live.\n - `Closed` — socket closed; the runtime will retry automatically.\n - `Failed err` — the WS endpoint refused or the chain rejected the filter;\n the runtime will NOT retry without an explicit `close + open` cycle.\n\n","args":[],"cases":[["Opening",[]],["Open",[]],["Closed",[]],["Failed",["String.String"]]]},{"name":"SubscriptionId","comment":" Opaque tag identifying a subscription. Construct with\n[`subscriptionId`](#subscriptionId).\n","args":[],"cases":[]}],"aliases":[{"name":"LogEvent","comment":" A single log event pushed by the subscription.\n\n`blockNumber` and `logIndex` are zero when unavailable (pending logs in\nsome node implementations). `removed` is `True` if a chain reorg made\nthis log no longer canonical — your update fn should usually treat a\nremoved log as an \"undo\" of an earlier emission.\n\n","args":[],"type":"{ address : Web3.Types.Address, topics : List.List String.String, data : String.String, blockNumber : Basics.Int, logIndex : Basics.Int, transactionHash : String.String, removed : Basics.Bool }"}],"values":[{"name":"atAddress","comment":" Narrow the filter to logs emitted by a specific contract.\n","type":"Web3.Types.Address -> Web3.Subscription.LogFilter -> Web3.Subscription.LogFilter"},{"name":"close","comment":" Close an open subscription by id. The runtime stops pushing events\nand (if the WS connection has no other active subscriptions) closes the\nsocket.\n","type":"Web3.Subscription.SubscriptionId -> Json.Encode.Value"},{"name":"eventDecoder","comment":" Decode a `{ tag: \"eventLog\", id, … }` port message into a\n`( SubscriptionId, LogEvent )` pair.\n","type":"Json.Decode.Decoder ( Web3.Subscription.SubscriptionId, Web3.Subscription.LogEvent )"},{"name":"logs","comment":" Start a logs filter that matches every log in every block. Refine with\n[`atAddress`](#atAddress) and [`withTopic`](#withTopic) — usually you want\nboth, otherwise you'll receive every event from every contract on the chain.\n","type":"Web3.Subscription.LogFilter"},{"name":"open","comment":" Open the subscription. Encodes to the `watchEvent` Cmd that\n[`elm-web3-ports.js`](https://github.com/intrepidshape/elm-web3/blob/main/js/elm-web3-ports.js)\nconsumes.\n","type":"Web3.Subscription.SubscriptionId -> Web3.Subscription.LogFilter -> Json.Encode.Value"},{"name":"statusDecoder","comment":" Decode a `{ tag: \"subscribed\", id, status }` port message into a\n`( SubscriptionId, Status )` pair.\n","type":"Json.Decode.Decoder ( Web3.Subscription.SubscriptionId, Web3.Subscription.Status )"},{"name":"subscriptionId","comment":" Build a `SubscriptionId` from a label. Labels must be unique within a\nsession; reusing a label closes the previous subscription with the same\nlabel.\n\n factorySid =\n Subscription.subscriptionId \"factory:TokenCreated\"\n\n","type":"String.String -> Web3.Subscription.SubscriptionId"},{"name":"subscriptionIdToString","comment":" Read the raw string back out of a `SubscriptionId`. Useful for routing\nincoming events in your `update` fn.\n","type":"Web3.Subscription.SubscriptionId -> String.String"},{"name":"withTopic","comment":" Match a specific topic at a given position. Topic 0 is always the event\nsignature hash; topics 1–3 are the event's indexed parameters in declaration\norder.\n\n -- match ERC-20 Transfer(address indexed from, address indexed to, uint256)\n Subscription.logs\n |> Subscription.atAddress tokenAddress\n |> Subscription.withTopic 0 transferTopic\n |> Subscription.withTopic 2 myAddressTopic\n\n","type":"Basics.Int -> String.String -> Web3.Subscription.LogFilter -> Web3.Subscription.LogFilter"},{"name":"withTopics","comment":" Replace the entire topics list with a pre-built list of optional topic\nhashes. `Nothing` at a position means \"match anything\" — use the variadic\n[`withTopic`](#withTopic) for the common case.\n","type":"List.List (Maybe.Maybe String.String) -> Web3.Subscription.LogFilter -> Web3.Subscription.LogFilter"}],"binops":[]},{"name":"Web3.Transaction","comment":" Transaction lifecycle state machine.\n\nEvery transaction goes through explicit states. Pattern matching forces you to\nhandle every case — no \"transaction failed silently\" bugs. The state machine\nfollows the TLA+ spec in `proofs/tla/TransactionSpec.tla`:\nterminal states never transition out (except via `TxReset`),\nand confirmation counts only increase.\n\n case tx.status of\n Idle ->\n viewBuyButton\n\n AwaitingSignature ->\n viewSigningSpinner\n\n Submitted hash ->\n viewPendingWithHash hash\n\n Confirming hash n ->\n viewConfirming n\n\n Confirmed receipt ->\n viewSuccess receipt\n\n Failed err ->\n viewError err\n\n Rejected ->\n viewRejected\n\nTo poll for a receipt after submission, encode a `RequestReceipt` command:\n\n case tx.status of\n Submitted hash ->\n ( model\n , web3Cmd (Tx.encodeCmd (Tx.RequestReceipt hash \"my-tx\"))\n )\n _ ->\n ( model, Cmd.none )\n\nTo reset a terminal transaction back to `Idle`:\n\n Tx.update Tx.TxReset tx.status\n\nRelated modules: `Web3.Contract.Send` to build and encode write calls;\n`Web3.Contract.Call` to simulate writes before broadcasting.\n\n@docs Status, Msg, TxCmd, Receipt, EventLog\n@docs update, isTerminal, isPending, transactionConfirmations\n@docs encodeCmd, decoder, parseReceiptEvents\n\n","unions":[{"name":"Msg","comment":" Messages from the JS transaction port.\n","args":[],"cases":[["TxSubmitted",["String.String"]],["TxConfirmation",["String.String","Basics.Int"]],["TxConfirmed",["Web3.Transaction.ReceiptJson"]],["TxFailed",["String.String"]],["TxRejected",[]],["TxReset",[]],["TxReceiptNotFound",["String.String"]]]},{"name":"Status","comment":" Transaction lifecycle status. Cannot be in an invalid state.\n","args":[],"cases":[["Idle",[]],["AwaitingSignature",[]],["Submitted",["Web3.Types.TxHash"]],["Confirming",["Web3.Types.TxHash","Basics.Int"]],["Confirmed",["Web3.Transaction.Receipt"]],["Failed",["String.String"]],["Rejected",[]]]},{"name":"TxCmd","comment":" Commands to send to the JS transaction port.\n","args":[],"cases":[["RequestReceipt",["Web3.Types.TxHash","String.String"]]]}],"aliases":[{"name":"EventLog","comment":" A single log entry emitted during a transaction.\n","args":[],"type":"{ address : Web3.Types.Address, topics : List.List String.String, data : String.String, blockNumber : Basics.Int, logIndex : Basics.Int }"},{"name":"Receipt","comment":" A confirmed transaction receipt, including emitted logs.\n","args":[],"type":"{ txHash : Web3.Types.TxHash, blockNumber : Basics.Int, gasUsed : String.String, status : Basics.Bool, logs : List.List Web3.Transaction.EventLog }"}],"values":[{"name":"decoder","comment":" Decode transaction messages from JS port.\n","type":"Json.Decode.Decoder Web3.Transaction.Msg"},{"name":"encodeCmd","comment":" Encode a TxCmd for the JS port.\n","type":"Web3.Transaction.TxCmd -> Json.Encode.Value"},{"name":"isPending","comment":" Is this status still pending?\n","type":"Web3.Transaction.Status -> Basics.Bool"},{"name":"isTerminal","comment":" Is this status terminal (no more updates expected)?\n","type":"Web3.Transaction.Status -> Basics.Bool"},{"name":"parseReceiptEvents","comment":" Apply a list of event decoders to the logs in a receipt, collecting\nall successfully decoded events.\n\n type MyEvent\n = Transfer { from : Address, to : Address, amount : BigInt }\n | Approval { owner : Address, spender : Address, amount : BigInt }\n\n decodeTransfer : EventLog -> Maybe MyEvent\n decodeTransfer log =\n -- match topic[0] to Transfer signature, then decode\n ...\n\n events : List MyEvent\n events =\n parseReceiptEvents [ decodeTransfer, decodeApproval ] receipt\n\n","type":"List.List (Web3.Transaction.EventLog -> Maybe.Maybe a) -> Web3.Transaction.Receipt -> List.List a"},{"name":"transactionConfirmations","comment":" Number of confirmations for a confirmed transaction given the current block number.\n","type":"Basics.Int -> Web3.Transaction.Receipt -> Basics.Int"},{"name":"update","comment":" Update transaction status from a port message.\n\nTransitions are guarded to match the TLA+ GuardedNext specification:\n- Terminal states (Confirmed, Failed, Rejected) never transition out, except via TxReset.\n- TxSubmitted is only accepted from AwaitingSignature.\n- TxConfirmation is only accepted from Submitted or Confirming.\n- TxFailed is accepted from any non-terminal state.\n- TxRejected from AwaitingSignature → Rejected; from Submitted/Confirming → Failed.\n- TxReset from any terminal state → Idle; from non-terminal states → no-op.\n- TxReceiptNotFound is a no-op; the app can schedule another RequestReceipt.\n","type":"Web3.Transaction.Msg -> Web3.Transaction.Status -> Web3.Transaction.Status"}],"binops":[]},{"name":"Web3.Types","comment":" Core opaque types for EVM interaction.\n\nAll types are opaque — you can't accidentally pass a `TxHash` where an `Address`\nis expected. Construction validates format and returns `Maybe` so invalid input\nis a compile-time-visible code path, not a runtime crash.\n\n import Web3.Types as T\n\n -- Validate on input boundary (e.g. from a URL param or user field):\n case T.address rawString of\n Just addr ->\n -- addr : T.Address — safe to use everywhere\n Nothing ->\n -- show validation error\n\n -- BlockNumber is used by Contract.Call, Block, Fee, and Query:\n T.encodeBlockNumber T.Latest == Json.Encode.string \"latest\"\n T.encodeBlockNumber (T.BlockNum 1000) == Json.Encode.int 1000\n\n`Wei` is an alias for `Web3.BigInt.BigInt` — use `Web3.Units.formatEther` to\nconvert to a human-readable string.\n\n@docs Address, TxHash, BlockNumber, ChainId, Wei, HexString\n@docs address, addressToString\n@docs txHash, txHashToString\n@docs chainId, chainIdToInt\n@docs hexString, hexStringToString\n@docs encodeBlockNumber\n\n","unions":[{"name":"Address","comment":" A validated Ethereum address (0x + 40 hex chars).\n","args":[],"cases":[]},{"name":"BlockNumber","comment":" A block number — specific or a tag.\n","args":[],"cases":[["BlockNum",["Basics.Int"]],["Latest",[]],["Pending",[]],["Earliest",[]]]},{"name":"ChainId","comment":" An EVM chain ID.\n","args":[],"cases":[]},{"name":"HexString","comment":" A raw hex string.\n","args":[],"cases":[]},{"name":"TxHash","comment":" A transaction hash (0x + 64 hex chars).\n","args":[],"cases":[]}],"aliases":[{"name":"Wei","comment":" Wei amount as a string (uint256 — too large for Int).\n","args":[],"type":"Web3.BigInt.BigInt"}],"values":[{"name":"address","comment":" Create an Address from a hex string. Returns Nothing if invalid.\n","type":"String.String -> Maybe.Maybe Web3.Types.Address"},{"name":"addressToString","comment":" Extract the string value of an Address.\n","type":"Web3.Types.Address -> String.String"},{"name":"chainId","comment":" Create a ChainId.\n","type":"Basics.Int -> Web3.Types.ChainId"},{"name":"chainIdToInt","comment":" Extract the integer value of a ChainId.\n","type":"Web3.Types.ChainId -> Basics.Int"},{"name":"encodeBlockNumber","comment":" Encode a BlockNumber for JSON-RPC (e.g. for eth_call block parameter).\n","type":"Web3.Types.BlockNumber -> Json.Encode.Value"},{"name":"hexString","comment":" Create a HexString.\n","type":"String.String -> Maybe.Maybe Web3.Types.HexString"},{"name":"hexStringToString","comment":" Extract the string value of a HexString.\n","type":"Web3.Types.HexString -> String.String"},{"name":"txHash","comment":" Create a TxHash from a hex string.\n","type":"String.String -> Maybe.Maybe Web3.Types.TxHash"},{"name":"txHashToString","comment":" Extract the string value of a TxHash.\n","type":"Web3.Types.TxHash -> String.String"}],"binops":[]},{"name":"Web3.Units","comment":" ETH / ERC-20 unit conversion — pure Elm, no JS required.\n\n formatEther (BigInt.fromInt 1500000000000000000) == \"1.5\"\n parseEther \"1.5\" == Just <1500000000000000000>\n\n@docs formatEther, parseEther\n@docs formatUnits, parseUnits\n\n","unions":[],"aliases":[],"values":[{"name":"formatEther","comment":" Convert Wei to a human-readable ETH string with up to 18 significant\ndecimal places. Trailing zeros are trimmed.\n\n formatEther zero == \"0\"\n formatEther (10^18 wei) == \"1\"\n formatEther (1.5×10^18) == \"1.5\"\n formatEther (10^15 wei) == \"0.001\"\n\n","type":"Web3.BigInt.BigInt -> String.String"},{"name":"formatUnits","comment":" Convert a token amount (in its smallest unit) to a human-readable string\nfor a token with the given number of decimal places. Trailing zeros are trimmed.\n\n formatUnits 6 (BigInt.fromInt 1500000) == \"1.5\" -- USDC\n formatUnits 8 (BigInt.fromInt 100000000) == \"1\" -- WBTC\n\n","type":"Basics.Int -> Web3.BigInt.BigInt -> String.String"},{"name":"parseEther","comment":" Parse a human-readable ETH string to Wei. Returns Nothing for invalid\ninput, non-numeric strings, or negative values.\n\n parseEther \"1\" == Just <10^18>\n parseEther \"1.5\" == Just <1.5×10^18>\n parseEther \"0.000000000000000001\" == Just (BigInt.fromInt 1)\n parseEther \"not-a-number\" == Nothing\n parseEther \"-1\" == Nothing\n\n","type":"String.String -> Maybe.Maybe Web3.BigInt.BigInt"},{"name":"parseUnits","comment":" Parse a human-readable token amount to its smallest unit, given the\ntoken's decimal count. Returns Nothing for invalid or negative input.\n\n parseUnits 6 \"1.5\" == Just (BigInt.fromInt 1500000) -- USDC\n parseUnits 6 \"0\" == Just BigInt.zero\n parseUnits 6 \"-1\" == Nothing\n\n","type":"Basics.Int -> String.String -> Maybe.Maybe Web3.BigInt.BigInt"}],"binops":[]},{"name":"Web3.Wallet","comment":" Wallet connection state machine.\n\nThe wallet is modeled as an explicit state — you can't accidentally\ncall a contract without a connected wallet because the compiler\nwon't give you an `Address` from a `Disconnected` state.\n\n case model.wallet of\n Connected info ->\n -- info.address : T.Address — only available here\n buy info.address amount\n\n WrongChain _ _ ->\n -- wallet is connected but on the wrong chain\n button [ onClick SwitchChain ] [ text \"Switch chain\" ]\n\n ReadOnly ->\n -- rpcUrl configured but no wallet; reads work, writes will fail\n viewReadOnlyBanner\n\n _ ->\n showConnectButton\n\n**EIP-6963 multi-wallet discovery** — listen for `WalletsDiscovered` on the\nport and present the list to the user; call `selectWallet rdns` when they pick.\n\n**Typical connection flow:**\n\n1. User clicks \"Connect\" → call `startConnect` on state, send `connect` via port.\n2. `WalletsDiscovered providers` arrives → show picker if `providers` is non-empty.\n3. User picks a wallet → send `selectWallet rdns` via port.\n4. `WalletConnected addr chainId` arrives → `update` transitions to `Connected` or `WrongChain`.\n5. If `WrongChain` → send `switchChain expectedChain` via port.\n\nFor native balance queries, use `Web3.Balance`. For adding chains, use `addChain` with\na `ChainConfig` record and follow up with `switchChain`.\n\n@docs State, Msg, WalletCmd, WalletProvider, ChainConfig\n@docs update, startConnect\n@docs connect, disconnect, switchChain, selectWallet, addChain\n@docs watchAsset, requestPermissions, getPermissions\n@docs isConnected, isReadOnly, getAddress, getChainId\n@docs encode, decoder\n\n","unions":[{"name":"Msg","comment":" Messages from the JS wallet port.\n","args":[],"cases":[["WalletConnected",["String.String","Basics.Int"]],["WalletDisconnected",[]],["ChainChanged",["Basics.Int"]],["AccountChanged",["String.String"]],["WalletError",["String.String"]],["WalletsDiscovered",["List.List Web3.Wallet.WalletProvider"]],["ReadOnlyMode",[]],["ChainAdded",[]],["SwitchChainOk",["Basics.Int"]],["AssetWatched",[]],["GotPermissions",["List.List String.String"]]]},{"name":"State","comment":" Wallet connection state. Every possible state is explicit.\n\n - `Disconnected` — no wallet detected, no rpcUrl configured\n - `ReadOnly` — rpcUrl is present but no wallet; reads work, writes will fail\n - `Connecting` — wallet connection in progress\n - `Connected` — wallet connected on the expected chain\n - `WrongChain` — wallet connected but on the wrong chain\n - `Error` — unrecoverable error\n\n","args":[],"cases":[["Disconnected",[]],["ReadOnly",[]],["Connecting",[]],["Connected",["Web3.Wallet.ConnectedInfo"]],["WrongChain",["Web3.Wallet.ConnectedInfo","Web3.Types.ChainId"]],["Error",["String.String"]]]},{"name":"WalletCmd","comment":" Commands to send to JS via port.\n","args":[],"cases":[["RequestConnect",[]],["RequestDisconnect",[]],["RequestSwitchChain",["Basics.Int"]],["RequestSelectWallet",["String.String"]],["RequestAddChain",["Web3.Wallet.ChainConfig"]],["RequestWatchAsset",["{ address : Web3.Types.Address, symbol : String.String, decimals : Basics.Int, image : String.String }"]],["RequestPermissions",[]],["GetPermissions",[]]]}],"aliases":[{"name":"ChainConfig","comment":" Configuration for adding a new chain to the wallet (EIP-3085).\n","args":[],"type":"{ chainId : Basics.Int, chainName : String.String, rpcUrls : List.List String.String, nativeCurrency : { name : String.String, symbol : String.String, decimals : Basics.Int }, blockExplorerUrls : List.List String.String }"},{"name":"WalletProvider","comment":" A wallet provider discovered via EIP-6963.\n","args":[],"type":"{ name : String.String, icon : String.String, rdns : String.String }"}],"values":[{"name":"addChain","comment":" Request wallet_addEthereumChain (EIP-3085) to add a new network.\n\n addChain\n { chainId = 369\n , chainName = \"PulseChain\"\n , rpcUrls = [ \"https://rpc.pulsechain.com\" ]\n , nativeCurrency = { name = \"Pulse\", symbol = \"PLS\", decimals = 18 }\n , blockExplorerUrls = [ \"https://scan.pulsechain.com\" ]\n }\n\n","type":"Web3.Wallet.ChainConfig -> Web3.Wallet.WalletCmd"},{"name":"connect","comment":" Command to request wallet connection.\n","type":"Web3.Wallet.WalletCmd"},{"name":"decoder","comment":" Decode a Msg from the JS wallet port.\n","type":"Json.Decode.Decoder Web3.Wallet.Msg"},{"name":"disconnect","comment":" Command to request wallet disconnection.\n","type":"Web3.Wallet.WalletCmd"},{"name":"encode","comment":" Encode a WalletCmd for the JS port.\n","type":"Web3.Wallet.WalletCmd -> Json.Encode.Value"},{"name":"getAddress","comment":" Extract the connected address, if any.\n","type":"Web3.Wallet.State -> Maybe.Maybe Web3.Types.Address"},{"name":"getChainId","comment":" Extract the connected chain ID, if any.\n","type":"Web3.Wallet.State -> Maybe.Maybe Web3.Types.ChainId"},{"name":"getPermissions","comment":" Command to get current wallet permissions (EIP-2255).\n","type":"Web3.Wallet.WalletCmd"},{"name":"isConnected","comment":" True if the wallet is in the Connected state.\n","type":"Web3.Wallet.State -> Basics.Bool"},{"name":"isReadOnly","comment":" True if in ReadOnly mode (rpcUrl present, no wallet). Reads work; writes will fail.\n","type":"Web3.Wallet.State -> Basics.Bool"},{"name":"requestPermissions","comment":" Command to request wallet permissions (EIP-2255).\n","type":"Web3.Wallet.WalletCmd"},{"name":"selectWallet","comment":" Command to select a specific wallet by its RDNS identifier (EIP-6963).\n\n selectWallet \"io.metamask\"\n\n","type":"String.String -> Web3.Wallet.WalletCmd"},{"name":"startConnect","comment":" Transition to `Connecting` state before sending the `connect` port command.\n\nCall this when the user clicks the connect button, then send `connect` via the port:\n\n ( { model | wallet = Wallet.startConnect model.wallet }\n , web3Cmd (Wallet.encode Wallet.connect)\n )\n\nValid transitions: `Disconnected → Connecting`, `Error _ → Connecting`.\nAll other states are unchanged (connecting while already connected is a no-op).\n\n","type":"Web3.Wallet.State -> Web3.Wallet.State"},{"name":"switchChain","comment":" Command to switch chain.\n","type":"Web3.Types.ChainId -> Web3.Wallet.WalletCmd"},{"name":"update","comment":" Update wallet state from a port message.\n","type":"Web3.Types.ChainId -> Web3.Wallet.Msg -> Web3.Wallet.State -> Web3.Wallet.State"},{"name":"watchAsset","comment":" Command to add a token to the wallet UI (EIP-747).\n","type":"{ address : Web3.Types.Address, symbol : String.String, decimals : Basics.Int, image : String.String } -> Web3.Wallet.WalletCmd"}],"binops":[]}]