Skip to content

Release: develop -> main#4308

Merged
TaprootFreak merged 2 commits into
mainfrom
develop
Jul 22, 2026
Merged

Release: develop -> main#4308
TaprootFreak merged 2 commits into
mainfrom
develop

Conversation

@github-actions

Copy link
Copy Markdown

Automatic Release PR

This PR was automatically created after changes were pushed to develop.

Commits: 1 new commit(s)

Checklist

  • Review all changes
  • Verify CI passes
  • Approve and merge when ready for production

…4228)

* feat(bank-account): reload bankAccounts with specific error result

* feat(bank-account): improve code
…W2W gas wallet (#3820)

* feat(realunit): add gasless wallet-to-wallet transfer with dedicated W2W gas wallet

Add user-initiated RealUnit (REALU) wallet-to-wallet transfer reusing the
existing gasless EIP-7702 relay mechanism, but paying gas from a dedicated,
separate W2W gas-funding wallet (never the Sell/OTC relayer).

- Config: REALUNIT_W2W_GAS_WALLET_PRIVATE_KEY / _ADDRESS / _LOW_BALANCE_THRESHOLD
- Thread an optional relayerPrivateKeyOverride into transferTokenWithUserDelegation
  (defaults to getRelayerPrivateKey, so Sell/OTC paths are unchanged)
- Persist transfer intent (RealUnitTransferRequest entity + migration): the blanket
  EIP-7702 delegation does not bind recipient/amount, so they are stored at prepare
  and relayed verbatim at confirm (never from untrusted client input)
- Endpoints PUT /v1/realunit/transfer and /transfer/:id/confirm (JWT + USER + active,
  KYC30 + registration gating, limit-exempt on-chain self-custody movement)
- Balance-monitoring observer with standard low-balance mail alert
- Jest specs + CONTRIBUTING route-taxonomy rows

* fix(realunit): address review on W2W transfer (deterministic migration names, typed caveats, KYC context)

- Use TypeORM deterministic sha1 constraint names in the transfer-request
  migration (PK/UQ/FK 27, IDX 26) instead of human-readable ones; update up + down
- Replace the DTO message.caveats `any[]` with a typed Eip712CaveatDto (enforcer + terms)
- Add KycContext.REALUNIT_TRANSFER and use it for the transfer registration/KYC
  exceptions instead of reusing REALUNIT_SELL
- Drop the unused getW2wGasWalletBalance service method (observer reads the balance itself)
- Stop loading user.userData in confirmTransfer (user is eager, userData unused)
- Fix import ordering in the service spec (realunit-dev before realunit)

* test(realunit): cover W2W transfer branches and relayer override to 100%

Add diff-coverage for every changed executable line and branch in the
W2W transfer flow:
- prepareTransfer/confirmTransfer: REALU asset-not-found, W2W gas wallet
  key/address unset (ServiceUnavailable), bare-key 0x normalization
- W2W gas observer: address-unset early return and mainnet (Ethereum)
  client branch
- eip7702 transferTokenWithUserDelegation: unsupported-chain throw,
  relayer-override path (W2W key used, not getRelayerPrivateKey) and
  default fallback
- contextRequiredSteps: REALUNIT_TRANSFER returns no extra steps
- thin controller delegations for the two transfer endpoints

* fix(realunit): set W2W transfer delegation delegate to the W2W gas wallet (fixes on-chain InvalidDelegate revert)

* fix(realunit): align W2W prepare user load with async registration gate

Registration is resolved via AktionariatRegistrationRepository on develop,
so prepareTransfer only needs userData (not kycSteps). Update the thin
controller spec and prettier-format the migration/CONTRIBUTING table.

* fix(realunit): harden W2W transfer against double-relay, gas drain and config drift

- confirmTransfer is now idempotent: atomic CREATED->PROCESSING claim, txHash
  persisted before broadcast (keccak256 of the signed tx), reverted receipts
  mark the request FAILED, and a 5-min reconciliation cron resolves stuck
  PROCESSING requests, so a retry/timeout/double-tap can no longer relay the
  blanket delegation twice.
- preflight the on-chain REALU balance and re-check the W2W gas wallet funding
  in confirm, so an under-funded sender can no longer drain the dedicated gas
  wallet via reverting relays.
- pin the delegation delegate to the W2W gas wallet and derive that wallet's
  address from its key (fail loud if REALUNIT_W2W_GAS_WALLET_ADDRESS disagrees).
- key the relayer nonce lock per account so the W2W path never blocks the
  Sell/OTC relayer.
- validate REALUNIT_W2W_GAS_LOW_BALANCE_THRESHOLD (fail loud instead of a silent
  NaN/0) and parse the confirm :id via ParseIntPipe.

* test(realunit): stub viem keccak256 in the eip7702 sell spec

The W2W hardening computes keccak256(signedTx) before broadcast; the sell
spec mocks viem and must provide keccak256 (returning the mocked
sendRawTransaction hash) so the post-broadcast hash assertion holds.

* fix(realunit): make W2W transfer reconciliation state changes atomic

- reconcile stale requests via a conditional update (status=PROCESSING, txHash IS NULL) instead of a full-entity save, so a concurrent confirm that has since persisted the txHash is never clobbered or wrongly marked FAILED
- apply the same conditional, PROCESSING-guarded transition to the receipt-confirmed and reverted paths

* fix(realunit): return 400 on W2W validation errors and require the gas threshold env

- map EIP-7702 delegation/authorization/signature validation failures to BadRequestException (400) instead of a raw 500 on the confirm endpoint
- fail loud when REALUNIT_W2W_GAS_LOW_BALANCE_THRESHOLD is unset instead of a silent 0.05 default; wire a jest env setup so specs keep constructing the config
- move the transfer-request migration after the latest migration on develop

* chore(migration): reorder the W2W transfer-request migration after the latest on develop

* fix(realunit): return 400 for insufficient REALU balance and document the W2W gas wallet env vars

- throw BadRequestException instead of ConflictException when the sender lacks enough REALU, consistent with the insufficient-gas check
- add the REALUNIT_W2W_GAS_WALLET_ADDRESS / _PRIVATE_KEY placeholders to .env.example
@TaprootFreak
TaprootFreak merged commit afa8e86 into main Jul 22, 2026
12 checks passed
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.

2 participants