Skip to content

Port onto @anyone-protocol/ao-client (D15/D16/D17) - #14

Open
jim-toth wants to merge 5 commits into
masterfrom
dev-hyper-aos-migration
Open

Port onto @anyone-protocol/ao-client (D15/D16/D17)#14
jim-toth wants to merge 5 commits into
masterfrom
dev-hyper-aos-migration

Conversation

@jim-toth

Copy link
Copy Markdown
Contributor

Fourth W4 port. Replaces @permaweb/aoconnect 0.0.59, the local send-aos-message.ts wrapper, and the vendored src/util/arbundles-lite with the shared client and the maintained @dha-team/arbundles.

D17 — explicit endpoints. CU_URL is gone, replaced by a single HB_URL with NO default (nodeUrlFromEnv fails closed).

This service's surface is claims, not rounds, so the mapping differs again from the three ports before it:

  • Get-Rewards (dryrun) -> the rewards?address= view. The view returns { address, reward }, so the amount is now a FIELD; the legacy dryrun made it the entire response body. An address with no rewards yields no reward key.

  • Claim-Rewards stays an action and still passes the beneficiary as a tag: the facilitator claims ON BEHALF of an address, so ctx.from is the facilitator and the handler is role-gated. Its return is the message output now, not Messages[1].Data.

  • relay returns a single claimed amount; staking returns the hodler's PER-OPERATOR map which the service sums. That asymmetry is in the contracts and is preserved.

The "no rewards" path is the interesting one. Both contracts assert 'No rewards for ', which arrives as an AoContractError — an HTTP 200 whose reason lives only in the message's own slot output. The old code inferred it from a missing Messages[1] and a substring match on result.Error; it is now an explicit branch on the error type, and still distinguishes "no rewards" (noReward: true) from a genuine rejection.

Both services build a READ-ONLY client when their controller key is absent rather than refusing to start — the key is optional on a non-hodler deploy, and getAllocation is a read. Previously the signer was simply left undefined.

Integration specs, 8/8 green against a local node holding the real migrated relay -rewards and staking-rewards state: allocations read back for a seeded address, claims return the real amounts (relay single, staking summed across operators and checked against the dump), an unknown address reads as undefined, and both services report noReward for one the contract has nothing for. Typecheck goes from 1 pre-existing error to zero.

jim-toth added 5 commits July 28, 2026 10:54
Fourth W4 port. Replaces @permaweb/aoconnect 0.0.59, the local send-aos-message.ts
wrapper, and the vendored src/util/arbundles-lite with the shared client and the
maintained @dha-team/arbundles.

D17 — explicit endpoints. CU_URL is gone, replaced by a single HB_URL with NO
default (nodeUrlFromEnv fails closed).

This service's surface is claims, not rounds, so the mapping differs again from
the three ports before it:

- `Get-Rewards` (dryrun) -> the `rewards?address=` view. The view returns
  { address, reward }, so the amount is now a FIELD; the legacy dryrun made it the
  entire response body. An address with no rewards yields no `reward` key.

- `Claim-Rewards` stays an action and still passes the beneficiary as a tag: the
  facilitator claims ON BEHALF of an address, so ctx.from is the facilitator and
  the handler is role-gated. Its return is the message output now, not
  Messages[1].Data.

- relay returns a single claimed amount; staking returns the hodler's PER-OPERATOR
  map which the service sums. That asymmetry is in the contracts and is preserved.

The "no rewards" path is the interesting one. Both contracts assert
'No rewards for <addr>', which arrives as an AoContractError — an HTTP 200 whose
reason lives only in the message's own slot output. The old code inferred it from
a missing Messages[1] and a substring match on result.Error; it is now an explicit
branch on the error type, and still distinguishes "no rewards" (noReward: true)
from a genuine rejection.

Both services build a READ-ONLY client when their controller key is absent rather
than refusing to start — the key is optional on a non-hodler deploy, and
getAllocation is a read. Previously the signer was simply left undefined.

Integration specs, 8/8 green against a local node holding the real migrated relay
-rewards and staking-rewards state: allocations read back for a seeded address,
claims return the real amounts (relay single, staking summed across operators and
checked against the dump), an unknown address reads as undefined, and both
services report noReward for one the contract has nothing for. Typecheck goes from
1 pre-existing error to zero.
Declared as a direct dependency but never imported — the Arweave interaction all
goes through the bundling service, which used the Turbo SDK.

No effect on `npm audit`: arweave stays in the tree transitively via
@ardrive/turbo-sdk and @dha-team/arbundles. This is declaration hygiene, so the
manifest says what the service actually uses.
Clears all 3 production criticals. These came from @dha-team/arbundles, which
pins the EOL @ethersproject v5 line; arbundles 1.0.4 is already latest and the
advisory range is `*`, so there was no upgrade to take — npm's suggested "fix"
is a downgrade to 1.0.3.

But the advisories are version-exact and both packages already ship fixes:

  elliptic     critical hits <=6.6.0, patched in 6.6.1
  secp256k1    high hits exactly 5.0.0, patched in 5.0.1

Both were installed twice — the patched version hoisted at the root, and a
vulnerable copy nested under arbundles that its ethersproject chain resolved to.
An override collapses them onto the patched ones, so this needs no change to
arbundles or to ethers (our own code is already on v6.17).

Verified rather than assumed: these are the ECDSA signing primitives, so a clean
build proves nothing. The integration specs were run against a real node holding
real migrated state, exercising ANS-104 signed writes end to end — operator
registry 5/5 (registration credits, operator certificates) and relay rewards 3/3
(settles a round, reads the snapshot back from the settle slot).

One low remains in elliptic with range <=6.6.1, i.e. unfixed at latest.
Declared but imported nowhere. GeoIpService does not use it — it fetches
/fingerprint-map/ from api-service over HTTP, so the geolocation data comes from
there, not from a local database.

It was the single largest source of production advisories left in this service.
It pulls rimraf 2 -> glob 7 -> minimatch 3 -> brace-expansion 1, and every high
in that chain came from it.

Its spec baseline is unchanged: 4 failed / 1 passed before and after, the
failures being pre-existing and requiring a live api-service at ANYONE_API_URL.

Production vulnerabilities: 1 high -> 0. This service has no geo-ip module at
all, so the dependency was pure inheritance.
Fixes a moderate prototype-pollution advisory in mongoose update casting, via
`__proto__`-prefixed dotted paths through Schema._getSchema. Affects 8.0.0 -
8.24.0.

This service was the only one left exposed, and not for an interesting reason:
the declared range `^8.7.2` already allowed the patched version, but its lockfile
still pinned 8.24.0 because its `npm audit fix` run was reverted earlier for
making the overall count worse. The other three controllers and api-service were
already on 8.24.2; operator-checks is on the 7.x line, which the advisory does
not cover.

No non-breaking fix was skipped here — `npm update mongoose` stays inside the
declared range.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant