1.2.0 - 2026-05-01
Public Surface Pass
Public Surface Pass bundle —
decode_event/4error contract narrowed. Thedecode_event/4@specpreviously declared{:ok, ...} | {:error, term()}, but the runtime path raised on malformed payloads instead of returning{:error, _}— so the typespec was a lie wherever a topic-matched log carried truncated/garbage data. Wrapped thedecode_raw-driven payload-decode path in atry/rescueand converted raised exceptions into{:error, {:malformed_data, message}}.verify_event_signature/2already returned{:error, ...}for signature mismatches but used a string format; tightened to the atom-tagged shape{:error, {:event_signature_mismatch, %{expected: ..., got: ...}}}so callers can pattern-match the failure mode without parsing strings. Added@type ABI.Event.decode_error/0enumerating the closed error set ({:event_signature_mismatch, _},{:topics_length_mismatch, _},{:malformed_data, _}); narrowedABI.decode_event/4's@specfrom{:error, term()}to{:error, Event.decode_error()}. Theapi()declaration now carries anerrors:block mirroringdecode_call/3's pattern, so the manifest exposes the closed error set to agent consumers. Bugfix-honoring-typespec — not a breaking change in any sensible sense (the prior contract was unreachable for malformed payloads), but downstream callers that previously caught raises arounddecode_event/4should switch to matching{:error, {:malformed_data, _}}.Public Surface Pass bundle —
encode_bytes/1flipped fromdeftodefp. Hygiene-only flip. Already@doc false(lib/abi/typeencoder.ex), zero callers outsidetype_encoder.exitself across the local monorepo (cartouche,onchain, `onchain{aave,evm,js,tempo},mpp), and the agent-economy hint-rot test had already excluded it as a deliberate internal helper. Thedefwas a leftover from beforeencode_raw/2became the canonical raw-encoding entrypoint. Removed the now-redundant@doc falseand the explicit exclusion entry fromtest/abi/agent_economy_test.exs(the function is no longer inmodule_info(:exports)`, so the hint-rot cross-check skips it naturally). Manifest user-declared count unchanged (already excluded). ROADMAP's "(breaking, if changed)" wording was overcautious — the codebase already treated this as internal.New API —
ABI.decode_error/2. Decodes Solidity 0.8.4+ custom-error revert data: matches the first-4-byte selector inrevert_dataagainst a list of known error definitions (signature strings or pre-parsedFunctionSelectorstructs, mixed accepted) and decodes the payload of whichever matches. Returns{:ok, %{error: name, args: [...]}}on a hit,{:error, :no_match}when no definition's selector matches (or the list is empty), and{:error, :calldata_too_short}on<4bytes. Mirrorsdecode_call/3's contract: malformed payload after a selector match still raises (same behavior asdecode/3). The first definition with a matching selector wins — definition order is the disambiguation lever. ReusesABI.method_id/1(selector computation),ABI.decode/3(payload decode),ABI.Parser.parse!/2(signature normalization).api()declaration carries the closed error set under namespace/abi. Solidity 0.8.4+ custom-error revert data is selector-prefixed exactly like calldata, so the implementation is structurally identical todecode_call/3modulo the multi-definition list.New API —
ABI.encode_packed/2. Solidity's non-standard packed encoding — used for Merkle airdrop leaves andkeccak256(abi.encodePacked(...))signature schemes. Per the spec: types <32 bytes concatenate tight (no padding); dynamic types (bytes,string) inline as raw payload (no length prefix); array elements are padded to 32 bytes (or 32-byte multiples forstring/bytes) so element boundaries are recoverable; tuples/structs and nested arrays are explicitly unsupported and raiseArgumentErrorwith a spec link. The wrapper accepts the same polymorphic first arg asencode/2(binary() | FunctionSelector.t()); paren-only signatures like"(uint256,address)"parse as a single-tuple parameter (same shape as"foo((uint256,address))") and therefore raise — pass a struct-arg-free signature like"foo(uint256,address)"for a comma-separated arg list. Cross-checked against the canonical spec example (int16(-1), bytes1(0x42), uint16(0x03), string("Hello, world!")→0xffff42000348656c6c6f2c20776f726c6421) and locked as a golden vector; Merkle-leaf golden vector (address ++ uint256→ 52 bytes pre-hash) included for airdrop consumers. Implementation lives next toencode_type/2inlib/abi/type_encoder.exwith privatepacked_top/2,packed_array/2,pack_uint/2,pack_int/2helpers — does NOT thread throughMath.pad/4(which always rounds to 32-byte multiples) since packed mode is the inverse of standard ABI. Inside an array, however, scalar elements DO route throughencode_type/2to reuse the 32-byte rounding correctly per spec.Property Suite Expansion bundle (5 members — original 4 plus a production fix the suite surfaced). Single PR expanding
test/abi/roundtrip_property_test.exsplus the resulting bug fix inlib/abi/type_decoder.ex.tuple[](dynamic array of tuples) round-trip coverage — the existing dispatcher already composes{:array, inner}with{:tuple, ...}, so no new generator clause was needed; what was missing was explicit pin-down. Three new properties: a static-only-elementtuple[](exercises the array-of-static-tuples layout), a mixed-elementtuple[]where each element is itself dynamic (the most stress-testing shape — head/tail offsets are computed both per-array AND per-element), and an emptytuple[]unit test. The mixed-element property is what surfaced the string-NUL bug below on its first run.- Empty dynamic fields inside structs — explicit fixtures (not properties) for the four pinned shapes that mining surfaced from real protocol calldata:
(bytes, string)with empty bytes and non-empty string,(bytes, bytes)both empty, emptytuple[]as the only dynamic field in a struct, and emptytuple[]followed by non-empty bytes. Inlinetest "..." doblocks rather than the@fixturespattern fromdefi_calldata_test.exs— round-trip equality is enough; no need to lock against synthetic byte strings when the property tests already exercise the layout invariants. - Multiple top-level struct args — added a
roundtrip_args/2helper alongside the single-argroundtrip/2. New property mirrors the Balancer V2swap(SingleSwap, FundManagement, uint256, uint256)shape: two sibling structs of differing dynamic-rate (one mixed static+dynamic, one static-only) plus two scalar args at the ends. Exercises sibling-tuple offset arithmetic when adjacent top-level tuples are dynamic at different rates —roundtrip/2always wrapped a single arg as[%{type: type}], so this layout was never exercised by the property suite. - Deep struct nesting (depth ≥ 4) round-trip — the recursive
compositeproperty'stype_and_value_gen(3)cap was bumped to depth 5 (PendleswapExactTokenForPtexercises depth 5 in real calldata).@tag timeout: 120_000 → 300_000to absorb the larger generation surface;max_runs: 50(down from the default 100) keeps CI bounded — depth-5 trees can balloon (lists of length 4 of strings up to 64 chars at multiple nesting levels), and 50 deep samples have higher information-density than 100 shallow ones. - Bug fix surfaced by the bundle:
ABI.TypeDecoderpreviously callednul_terminate_string/1on every decoded:string, splitting the binary at the first<<0>>byte and returning only the prefix. This treated Solidity strings as C strings — wrong. Per the Solidity ABI spec, strings are length-prefixed UTF-8 and may legally contain NUL codepoints (U+0000); the length is exact, so right-padded zeros after the data are the only NULs that need stripping (anddecode_bytes/3 → Math.unpad/3already handled that). Removed thenul_terminate_string/1helper entirely; the:stringdecode clause now delegates straight todecode_bytes(rest, length, :right). Pre-existing in upstreamexthereum/abisince 2018 (commitbdceb719by Levi Aul) — undetected because randomStreamData.string(:utf8, ...)rarely starts with NUL, and most real Solidity strings (function names, error messages, event signatures) don't either. The mixed-elementtuple[]property happened to generate a NUL-prefixed string and surfaced it. Three regression unit tests added: leading-NUL string, embedded-NUL string, and all-NULs string. Production paths affected:ABI.decode/3,ABI.decode_call/3,ABI.decode_event/4,ABI.TypeDecoder.decode/3— anywhere a:stringis decoded. Should be filed upstream alongside #53/#54/#55 (or batched with the lexerxsub-bug) — affects everyexthereum/abiconsumer that decodes user-supplied strings.
DeFi Real-World Fixtures bundle. Tests-only addition; no production code touched. Closes both members of the bundle in a single commit.
test/abi/defi_calldata_test.exs— 10 round-trip golden vectors captured fromdefi-skills build --action <name> --json(defi-skills v0.3.0). Fixtures live inline as@fixtures(the originally-proposedtest/fixtures/defi_calldata.exsshape was discarded — no.exsdata-loading idiom exists in the repo and inline matches the existing test convention). Each fixture asserts both directions:ABI.encode(sig, args)reproduces the locked calldata byte-for-byte andABI.decode_call(sig, calldata)recovers the original args. Coverage: Aave V3 supply/borrow/setCollateral, Compound V3 supply/claim, Lido stake/unstake (the only fixture exercisinguint256[]head/tail layout), EigenLayer deposit, ERC-20 transfer, WETH unwrap. The aave_supply fixture reproduces the calldata locked in the ROADMAP planting note byte-for-byte.test/abi/function_selector_real_world_test.exs— 12 explicitABI.method_id/1golden-vector assertions: ERC-20 (transfer,transferFrom), Aave V3 (supply,borrow), WETH/Curve gauge (withdraw(uint256)— duplicate selector by design), WETH/Rocket Pool (deposit()— duplicate by design), Lido (requestWithdrawals(uint256[],address)), Compound V3 (claim), Curve 3pool (add_liquidity(uint256[3],uint256)— fixed-size-array path), Uniswap V3 (exactInputSingle(tuple)— single tuple arg), Balancer V2 (swap— multiple top-level tuples), and EigenLayer (queueWithdrawals(tuple[])— dynamictuple[]). A seconddescribeblock round-trips the four tuple/tuple[]/fixed-array signatures throughFunctionSelector.decode/1 ∘ encode/1and re-asserts the selector — the 4 corner-case canonical-signature shapes were the entire reason the selector vectors are scoped this widely.- Why ship this. Before this bundle,
hieroglyphhad a single mainnet-style fixture in the entire test suite (the ERC-20Transferevent doctest inlib/abi.ex). Every encoder/decoder change was verified only against synthetic property-suite shapes. Real-world contract evidence now lives next to the synthetic suite, giving cartouche / onchain CI a stable contract-stability surface across hieroglyph version bumps. The 4 tuple-bearing selectors specifically prove the canonical-signature serialization infunction_selector.exmatches what real chains expect.
Agent Economy
Agent Economy — Phase 1: Descripex on
ABItop-level. Annotated the seven public functions (encode/2,method_id/1,decode/3,decode_call/3,decode_event/4,event_signature/1,parse_specification/1) withapi()declarations under namespace/abi. Six of the seven take a polymorphic first arg (binary() | FunctionSelector.t()); the union is described in prose per the established mpp/mcppayment_required_error/1precedent (oneapi()block per function name; the formal union lives on@spec).ABInowusesDescripex.Discoverablewith a single-module list — Phase 2 expands the list to all six annotated modules. Existing@docblocks (with their doctests) preserved by ordering:api()first emits its generated@doc, then the manual@doc """..."""overrides slot 4 prose while@doc hints:survives via descripex's__before_compile__ETS injection.@specand runtime behaviour unchanged. Manifest emission viamix descripex.manifest --app hieroglyphalready works (returns 7 ABI entries plus the four Discoverable bookkeeping exports); the dedicatedmix hieroglyph.manifesttask lands in Phase 3. Doctor docs/specs coverage held at 100/100, dialyzer 0 warnings, credo--strict0 issues. New runtime dep:{:descripex, "~> 0.6"}(transitively pulls:json_spec). Version bumped from1.1.x→1.2.0because adding a runtime dep changes downstream consumers' (cartouche, onchain) dependency closure.- Agent Economy — Phase 2: Descripex on the remaining five modules. Annotated all 18 documented public functions across
ABI.Event(/selector— 3 fns),ABI.FunctionSelector(/selector— 5 fns; the three@doc falseinternalsdynamic?/1,get_function_type/1,get_state_mutability/1deliberately excluded),ABI.TypeEncoder(/codec— 2 fns;encode_bytes/1@doc falseexcluded),ABI.TypeDecoder(/codec— 4 fns), andABI.Math(/math— 4 fns). None of these 18 functions are polymorphic, so eachapi()block follows the standard shape — name, one-sentence description,params:keyword list,returns:map.composes_with:links wired across the natural pairings:Event.decode_event ↔ event_signature,FunctionSelector.decode ↔ encode,TypeEncoder.encode ↔ encode_raw,TypeDecoder.decode ↔ decode_raw. Extendeduse Descripex.Discoverable, modules: [...]inlib/abi.exfrom[ABI]to all six annotated modules. Manifest now emits the full 25 user-declaredapi()entries (7 + 3 + 5 + 2 + 4 + 4) plus the 4 frameworkDiscoverableexports — verified viamix descripex.manifest --app hieroglyphand per-module entry counts.@doc/doctest preservation pattern from Phase 1 carries through: existing@doc """..."""blocks override slot 4 prose;@doc hints:survives. No behaviour change, no@specchange. - Agent Economy — Phase 3: dedicated manifest task + hint-rot validation test. New mix task
mix hieroglyph.manifest [path](defaults toapi_manifest.json) emits the JSON manifest usingABI.__descripex_modules__/0as the single source of truth — direct port of the establishedmix mpp.manifestshape. Manifest is suitable for downstream cartouche/onchain CI to diff across hieroglyph version bumps as a contract-stability artifact. New test filetest/abi/agent_economy_test.exsenforces the agent-discovery surface in three describe blocks plus a load-bearing cross-check: (1) every entry in each module's__api__/0carries:hints.description; (2)ABI.describe/0..2returns the expected modules / function lists / per-function detail; (3) namespaces (/abi,/selector,/codec,/math) match per-module assignments viaCode.fetch_docs/1. The cross-check walksmodule_info(:exports), strips Elixir/Descripex framework exports, plus an explicit allow-list of the four@doc falseinternal helpers (FunctionSelector.dynamic?/1,get_function_type/1,get_state_mutability/1,TypeEncoder.encode_bytes/1), then asserts every remaining export is declared withapi()— without this gate, hints rot silently when newdefs land withoutapi(), and silent rot here propagates as silent contract drift through cartouche-generated bindings into every onchain_<protocol> package. - Bug fix (sub-bug of upstream #54, upstream filing deferred — will be batched into a future combined-bugs issue with PR offer):
ABI.FunctionSelector.decode_type("fixed128x18")anddecode_type("ufixed256x80")(and the same-shape forms inside arrays/tuples/function signatures) raised a leakyFunctionClauseErrorinstead of the friendlyArgumentErrorthat barefixed/ufixedalready produced. Root cause was lexer rule ordering insrc/ethereum_abi_lexer.xrl: the LETTERS rule ([a-zA-Z_]+) was listed before the standalone'x'terminal, so leex picked LETTERS on equal-length matches and the singlexbetween the two integers tokenized asletters. The grammar ruletype -> typename digits 'x' digitsnever fired, the parser fell through tojuxt_type(fixed, 128), andjuxt_type/2had nofixedclause. Fix: introduced dedicatedfixed_typename/ufixed_typenameterminals (so the'x'separator is only valid infixed/ufixedcontexts), moved the'x'rule above{LETTERS}, and extended the parser'sidentifier_partto also accept'x',fixed_typename, andufixed_typenameso single-charxand the keyword forms still work as function/argument names. The explicit-M/N forms now route throughABI.Parser.reject_unsupported!/1and raise the same friendlyArgumentError(with the upstream-#54 link) that the bare forms already produced. Yecc reports 3 shift/reduce conflicts (was 1) — the 2 new ones come fromfixed_typename/ufixed_typenamebeing able to start either atypeor anidentifier_part; yecc's default shift resolution is the desired behavior (fixed128is a type prefix, not an identifier), and is documented inline in the.yrlExpect 3.comment. Regression tests added: explicit-M/N rejection (fixed128x18,ufixed256x80) plusx-keyword identifier handling (function namedx, argument namedx, function namedfixed/ufixed, and a function name containingxmid-string).
1.1.0 - 2026-05-01
- Bug fix (upstream #55):
ABI.TypeEncoder.encode_int/2rejected ALLint<N>values (including0) for small bit widths, because the overflow guard mixed up bytes and bits — it comparedbyte_size(significant_bytes)againstdesired_size_bytes - 1, which evaluates to0forint8, raising on every input. Replaced with a numeric range check against2^(N-1)performed up-front, so the encoder accepts the full signed range-2^(N-1)..2^(N-1)-1for everyint<N>. The pre-existing"int overflow raises data overflow"test passed only because the encoder was broken for any value; tightened the test to assert specific in-range values encode AND specific boundary cases (128,-129) raise. - Bug fix:
ABI.FunctionSelector.dynamic?/1raisedFunctionClauseErroron{:array, T, 0}(zero-length fixed array). The grammar acceptsT[0](yrl rule allowsN >= 0), so the type is parseable, but the existing clauses requiredlen > 0and no clause matched the zero case. Addeddef dynamic?({:array, _type, 0}), do: false— a zero-length fixed array has no head/tail layout and no payload, so it is static by any sensible definition. Encoder and decoder paths already handle zero-length arrays (encode_type({:array, _, 0})produces an empty repeated-type tuple;decode_type({:array, _, 0}, data, _opts) -> {[], data}); verified by extendingroundtrip_property_test.exs's fixed-array length domain from1..3to0..3. Pre-existing in upstreamexthereum/abi; not yet filed. ABI.FunctionSelector.@type typenow carries a@typedocclarifying thataddress payablecollapses to:address. Solidity's ABI JSON only emits"address"for both forms, the on-the-wire encoding is identical (20-byte left-padded), and payability is a property ofstate_mutabilityrather than a separate type variant — so consumers shouldn't expect a distinct atom.- Added
test/abi/roundtrip_property_test.exs— property-baseddecode(encode(x)) == xcoverage usingstream_datafor every type inABI.FunctionSelector.@type type/0:uint,int,address,bool,string,bytes,bytesN, fixed and dynamic arrays, and recursively nested tuples (depth ≤ 3). Per-type properties localize failures to a single clause; the recursive composite property exercises nested{:tuple, [{:array, ...}]}shapes where head/tail offsets matter. Surfaced theencode_intbug above on its first run. Test-only dep{:stream_data, "~> 1.1"}added. - Test coverage for the empty-args calldata path (
f()shape — 4-byte selector with zero ABI-encoded args).weth.deposit()(selector0xd0e30db0),rocket_pool.deposit(), and similar zero-arg calls were untested by the round-trip property suite (every generator produced at least one value). Pinned both directions:ABI.encode("deposit()", []) == <<0xD0, 0xE3, 0x0D, 0xB0>>andABI.decode("deposit()", <<>>) == [], plus thefunction: nil/types: []empty-bytes shape. - Test coverage for
FunctionSelectorselector-rendering and parser edge cases:encode/1canonical-signature rendering of{:int, N},{:struct, _, _, _}, dead-via-parse types (:function,{:fixed, M, N},{:ufixed, M, N}) andnil-typed slots (defensive against partially-built typeinfo maps); plusparse_specification/1's%{"indexed" => _}-without-"name"branch (older Solidity versions and hand-written ABIs may omit names on indexed event params). - New API:
ABI.method_id/1returns the 4-byte function selector (keccak256(canonical_signature)[0..3]) for a signature string orFunctionSelectorstruct. Returns<<>>for selectors withfunction: nil. Previously the same logic was private toABI.TypeEncoder; exposing it is a useful primitive for callers that need to compute selectors without encoding args (selector-table routing, log-topic matching, calldata pre-validation). - New API:
ABI.decode_call/3is the symmetric counterpart toABI.encode/2for selector-prefixed calldata. Splits the 4-byte prefix, verifies it matches the expected selector, and decodes the payload via the existingdecode/3machinery. Returns{:ok, decoded}on match or{:error, reason}for:calldata_too_short(< 4 bytes),:selector_mismatch(prefix wrong), or:no_function_name(selector hasfunction: nil, so there's nothing to verify against — caller should usedecode/3with the payload).ABI.decode/3semantics are unchanged: it remains payload-only, matchingeth-abi/ethers/viem/alloyconventions.
1.0.0 - 2026-04-24
First hex.pm release as hieroglyph. This is a maintained fork of exthereum/abi; the module namespace is unchanged (ABI.encode/2, ABI.decode/2, etc. — consumers just swap the hex dep name). Version resets to 1.0.0 under the new package name; the 1.0.0-alpha* / 1.0.0-bravo1 lines below this entry are the upstream's pre-release history, carried forward for context but never published to hex under hieroglyph.
- Published as
hieroglyph— hex package renamed from the internalabiapp name. Top-level moduleABIpreserved (the Solidity term is the correct module name). Repo renamed toZenHive/hieroglyph; upstreamexthereum/abitracked in the package's "Upstream (fork-of)" link. - Bug fix (upstream #53):
ABI.Event.decode_event/4now returns{:indexed_hash, <<32 bytes>>}for indexed parameters of reference type (string,bytes, all arrays — fixed-size or dynamic — and tuples/structs) instead of silently misdecoding the keccak topic as if it were a raw ABI-encoded value. Per the Solidity ABI spec, indexed reference-type values are stored in topics askeccak256(value)and the original is unrecoverable — the tagged tuple preserves the hash (useful for log filtering and equality checks) and makes the "unrecoverable" signal pattern-matchable. This is broader than the ABI head/tail "dynamic" rule:uint256[2]and tuples of all-static members are static for regular ABI encoding but are still hashed in event topics, and this fix handles both. Breaking for callers that consumed the previous garbage bytes directly; static value-type indexed params (uint/int/address/bool/bytesN/function/fixed/ufixed) are unchanged. Regression tests added for indexedstring, indexedbytes, indexed dynamic array, indexed fixed-size static array (uint256[2]), indexed tuple of static members, and mixed static+dynamic+non-indexed cases. - Bug fix (upstream #54):
fixed,ufixed, andfunctiontypes now raiseArgumentErrorat parse time (inABI.Parser.parse!/2, walking nested arrays and tuples) with a link to the tracking issue, instead of parsing silently into unsupported internal terms and later raising the cryptic"Unsupported encoding type"insideTypeEncoder/TypeDecoder. Also filled the{:bytes, pos_integer()}gap inABI.FunctionSelector.@type type— previously omitted even though fully supported by the encoder and decoder. Note: the explicitfixed<M>x<N>/ufixed<M>x<N>forms still raise aFunctionClauseErrorupstream of this walker due to a separate pre-existing lexer-rule-ordering bug (singlextokenizes aslettersinstead of the'x'terminal) — tracked as a follow-up task. Also aligned the grammar's bare-fixed/ bare-ufixedcanonical expansion to the Solidity spec (fixed128x18/ufixed128x18; previouslyx19) so the rejection error message reports the correct form. - Simplified
ABI.Parser.parse!/2's unsupported-type walker to drop a deadis_list(returns)branch — the yecc grammar only emitsnilor a single bare type forreturns, never a list. No behavior change. - Extracted the 32-byte padding logic into
ABI.Math.pad/4andABI.Math.unpad/3.ABI.TypeEncoder.encode_bytes/1,encode_int/2, andencode_uint/2now delegate toABI.Math.pad/4;ABI.TypeDecoder.decode_bytes/3is a thin wrapper aroundABI.Math.unpad/3. No behavior change; resolves the long-standingTODO: add to ABI.Mathcomments in both modules. - Renamed
ABI.FunctionSelector.is_dynamic?/1toABI.FunctionSelector.dynamic?/1to satisfyCredo.Check.Readability.PredicateFunctionNames. The function remains@doc false(internal). No deprecation shim — the old name had@doc falsesince 2017 and zero in-repo references outside three private call-sites, which were updated. - Drove
mix credo --strictto zero violations (was 51). CoversDesign.AliasUsage(top-of-module aliases added acrossABI,ABI.Event,ABI.FunctionSelector,ABI.Parser,ABI.TypeDecoder,ABI.TypeEncoder, andABI.Hex),Readability.MaxLineLength(spec / docstring wraps + the bigEnum.reducetuple-encoder broken into anencode_tuple_element/2helper),Consistency.ParameterPatternMatching(flipped threerecord = %{…}heads to%{…} = record), andRefactor.Nesting(extractedABI.Event.verify_event_signature/2andABI.TypeEncoder.fetch_named_field/2+fetch_by_name/2helpers to drop nesting below 3). - Added regression tests for the map-input encoder path (
ABI.TypeEncoder.data_to_list/2): atom-keyed maps, string-keyed maps, camelCase→snake_case name resolution, string-over-atom key priority, integer values inside nested named-struct maps, and the missing-field / unnamed-type error raises. The map branch previously had zero test coverage; the string-key path was added in commit46accc8, and this suite also exercises integer encoding (a43e9d5) through the map branch. - Added
@spectypespecs and@docstrings for every previously-undeclared public function acrossABI,ABI.Event,ABI.TypeDecoder,ABI.TypeEncoder, andABI.FunctionSelector:ABI.event_signature/1,ABI.parse_specification/1,ABI.TypeDecoder.decode/3,ABI.TypeDecoder.tuple_value/3,ABI.TypeEncoder.encode_raw/2,ABI.Event.decode_event/4/event_signature/1/canonical/2, andABI.FunctionSelector.decode/1/decode_raw/1/parse_specification_item/1/decode_type/1/encode/3; also added docs forTypeDecoder.tuple_value/3andTypeDecoder.decode_bytes/3. Matches the style widened in PR #52. Doctor spec coverage 42% → 88%, doc coverage 88% → 96%. - Added regression tests for eleven previously-uncovered error paths:
boolwith non-boolean values,bytes<N>size mismatches and wrong-datatype values, unsupported type atoms across encoder / decoder / function-selector, int/uint overflow, trailing decode data, anddecode_event/4returns for mismatched event signatures and invalid topic counts. - README refreshed: dropped the stale "tuples with multiple elements don't parse" caveat (false since JSON-ABI support), corrected
ABI.encode/2arity and flippedbytes<M>to supported in the Support checklist, migrated deadsolidity.readthedocs.iolinks todocs.soliditylang.org, and added runnable examples forABI.parse_specification/1,ABI.Event.decode_event/4, and map/struct input toencode/2.
1.0.0-bravo1
- Fix ABI tuple encoding for nested inlined tuples
1.0.0-alpha9
- Add Names to Event Signatures
1.0.0-alpha8
- Add Event Signature check to ABI.Event.decode_event
- Change
decode_eventto return an {:ok, event_name, event_params} tuple. - Add ability to add
"indexed"keyword to ABI canonicals
1.0.0-alpha7
- Bugfix for event decoding with dynamic parameters
1.0.0-alpha6
- Bugfix for is_dynamic
0.1.15
- Properly treat all function encodes as tuple encodings
0.1.14
- Fix 0-length
type[]encoding
0.1.13
- Drop dependency on exth crypto and move in functionality
0.1.12
- Fix
stringdecoding to truncate on encountering NUL - Fix some edge-cases in
tupleencoding/decoding
0.1.11
- Add support for method ID calculation of all standard types
0.1.10
- Fix parsing of function names containing uppercase letters/digits/underscores
- Add support for
bytes<M>
0.1.9
- Add support for parsing ABI specification documents (
.abi.jsonfiles) - Reimplement function signature parsing using a BNF grammar
- Fix potential stack overflow during encoding/decoding
0.1.8
- Fix ordering of elements in tuples
0.1.7
- Fix support for arrays of uint types
0.1.6
- Add public interface to raw function versions.
0.1.5
- Bugfix so that addresses are still left padded.
0.1.4
- Bugfix for tuples to properly handle tail pointer poisition.
0.1.3
- Bugfix for tuples to properly handle head/tail encoding
0.1.2
- Add support for tuples, fixed-length and variable length arrays