Repository navigation
fix(taip-5): require for on address agents - #15
Merged
Merged
Conversation
thomasjsk
force-pushed
the
fix/taip5-require-agent-for
branch
from
September 11, 2026 18:04
3209ac6 to
f1a4d06
Compare
for attribute on every agentfor on address agents, and stop dropping it
thomasjsk
marked this pull request as ready for review
September 11, 2026 18:10
thomasjsk
force-pushed
the
fix/taip5-require-agent-for
branch
from
September 11, 2026 18:14
f1a4d06 to
2f30983
Compare
for on address agents, and stop dropping itfor on address agents
thomasjsk
force-pushed
the
fix/taip5-require-agent-for
branch
from
September 11, 2026 18:17
2f30983 to
e5e1518
Compare
TAIP-5 marks `for` REQUIRED on every agent, and this library never checked it. Agents went out without one and nothing complained — including settlement addresses, where `for` is the only thing telling a receiver whether a customer holds the keys or their VASP does. Every constructor that carries agents now validates them: Transfer, Payment, Connect, Quote, RFQ, AddAgents, Lock, UpdateAgent and ReplaceAgent. The last three validated nothing at all before. `for` is enforced on the blockchain-address roles rather than on every agent. The spec has no way to say that who owns an agent is not established yet, which is a state real flows pass through — an address can be seen before anybody has resolved who custodies it, and an institution can join a transaction before it says whose behalf it acts on. Demanding `for` there would mean inventing an owner, and an invented one is worse than an absent one: a receiver stores it as fact, and it decides whether a wallet must prove ownership or must not. Whoever supplies an address does know whose it is, so that is where the line sits. An empty DID inside `for` is rejected whatever the role. Validation is send-side only. ParseBody accepts inbound agents without `for` regardless of role, so peers that do not set it keep working. Also retags UpdatePartyBody.Role to `partyType` per TAIP-6. The `role` spelling matched no other implementation, so these messages were silently ignored by conformant peers; inbound bodies still read `role` as a fallback.
thomasjsk
force-pushed
the
fix/taip5-require-agent-for
branch
from
September 11, 2026 18:19
e5e1518 to
62d48a1
Compare
momilo
approved these changes
Sep 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TAIP-5 says every agent MUST carry
for— the DID of whoever it acts on behalf of. This library tagged the fieldomitemptyand never checked it, so agents went out without one and nothing complained. That matters most on a settlement address:foris what tells a receiver whether a customer holds the keys or their VASP custodies it, and the two Notabene nodes read a missing one in opposite directions — one assumes custodial, the other assumes self-hosted and demands an ownership proof.Every constructor that carries agents now validates them — including
NewLockMessage,NewUpdateAgentMessageandNewReplaceAgentMessage, which validated nothing at all before. (#13 already fixed the marshalling half, so an ownerlessforomits the key rather than shippingnull.)Required on addresses, not on everything
foris enforced on the blockchain-address roles (SourceAddress,SettlementAddress) rather than on every agent, and this is a deliberate divergence from the letter of TAIP-5.The spec has no way to say that who owns an agent is not established yet, which is a state real flows pass through: an address can be seen before anybody has resolved who custodies it, and an institution can join a transaction before it says whose behalf it acts on. Enforcing
forthere would force implementations to invent an owner — and an inventedforis worse than an absent one, because a receiver stores it as fact and it decides whether a wallet must prove ownership or must not.Whoever supplies a blockchain address does know whose address it is, so that is where the line sits. An empty DID inside
foris rejected whatever the role.Worth settling upstream: should
forbe strictly REQUIRED, or should an agent pending ownership resolution be expressible? The spec is already inconsistent here — the JSON schemas list only@idas required, while the prose marksforREQUIRED too.Send-side only
ParseBodyis unchanged and still accepts inbound agents withoutfor, whatever the role. Other implementations treat the field as optional — the TypeScript reference types declare itfor?: string, and at least one inbound validator checks it only "when present" — so rejecting on receive would drop traffic that is valid today.UpdatePartyused the wrong field nameTAIP-6 calls the field
partyType; this library called itrole. A conformant peer looking forpartyTypefound nothing and could not tell which party the update was about, so these messages were effectively dropped. Renamed, with inbound bodies still readingroleso peers on the old spelling keep working.Deliberately not here
LockandRFQkeep their names. The spec onmaindefines#Lock(TAIP-17) and#RFQ(TAIP-18); the rename toEscrow/Exchangeexists only on an unmerged branch, so following it now would break interop rather than fix it.lei:leiCodekeeps its prefix. TAIP-11 contradicts itself — the JSON schemas saylei:leiCode, one prose example saysleiCode— and this library follows the schemas.amounton Transfer stays unvalidated. TAIP-3 makes it required for fungible tokens but optional for NFTs, and an NFT is not reliably detectable from a CAIP-19 string, so a blanket check would reject valid NFT transfers.Breaking
An address agent without
fornow returns an error instead of going out malformed, andUpdatePartyBody.Roleis nowPartyType.