myXRP Formal Review
Formal-methods case study
Formal review of the sealed Flare bridge. Properties held. This is a code review. The note stays with the published bridge.
Protocol Defence reviewed the live myXRP bridge on Flare as a closed system: one immutable FXRP pipe, one 1:1 receipt ledger, one immutable ceiling, and a public desk that must name the same contract. This is a formal-methods engagement — we wrote the properties first, then asked whether the deployed Solidity and the published site satisfy them.
This is a code review. The note stays with the published bridge. Every property we stated holds on the live bytecode, or is an accepted observation that does not move value. There is no hidden mint, no retargetable underlying, no admin key, and no stranger-reachable drain.
Engagement
Desk: Protocol Defence. Method: source-assisted bytecode review, predicate discharge on every state-changing path, and a walk of the public surfaces a counterparty actually clicks. Report closed 1 October 2026 at 14:25 UTC, after this address was deployed on 30 September 2026.
- Network. Flare C-Chain,
chainId = 14. - Compiler. Solidity
^0.8.20, overflow checks on, custom errors on the hot paths. - Contract.
MyXRPBridgeat 0x14b9DD90edaAff6527c1b168550B3FAA15b9F6AF. - Underlying. Official Flare FXRP 0xAd552A648C74D49E10027AB8a618A3ad4901c5bE, 6 decimals, bound
immutable. - Ceiling.
maxAssetsimmutable at 10,000,000.000000 FXRP (10_000_000_000_000raw). Read live withmaxAssets(). It is not a figure from an earlier deployment. - Public desk. myxrp.fi — deposit panel, add-to-wallet,
/explorer-verify/,/token.json.
Severity at close: 0 critical, 0 high, 0 medium, 0 low. Two formal notes (KF-N1, KF-N2) record the constant name and the withdraw order. Neither requires a patch.
What we specified
The bridge is not a rebasing vault and not ERC-4626. We treated it as a small machine with one balance map and two immutables:
underlying— the FXRP pipe, fixed at deploy.maxAssets— the mint ceiling, fixed at deploy.- External units:
balanceOf(u)is the stored balance. There is no index and no preview of unapplied yield.
Properties we discharged against the live selectors:
- P-Bind.
underlyingis immutable. After deploy, nobody can retarget the bridge onto a spoof ERC-20. - P-Cap.
maxAssetsis immutable.depositrevertsCapExceededwhentotalSupply + amountwould pass it. There is no setter. - P-OneToOne.
deposit(a)pullsaFXRP and mintsamyXRP.withdraw(a)burnsaand pushesaFXRP. A zero amount revertsZeroAmount. - P-Cash. If
underlying.balanceOf(this) < a,withdrawrevertsInsufficientLiquiditybefore the burn is committed. - P-NoAdmin. The runtime has no owner, no admin sweep, no accrual, no supply setter, and no pause.
- P-Reenter.
depositandwithdrawarenonReentrant. A nested call revertsReentered. - P-Room.
room()equalsmaxAssets - totalSupply. - P-NoProxy. No upgrade proxy, no
delegatecall, noselfdestruct, no leftoverinitialize, notx.originauth, no fee-on-transfer. - P-Label.
name()andsymbol()are the constantmyXRP. The receipt is a Flare bridge claim on FXRP locked in this contract. It is not native XRP and not an XRPL IOU. - P-StuckGift. A raw FXRP transfer into the contract does not mint. Surplus above
totalSupplycannot be extracted, because the only outbound path pays 1:1 against a burn.
All ten hold on the published source and the runtime at this address. A reader can open the Flare explorer contract tab and repeat the check. The bytecode at this address did not exist before 30 September 2026, 15:00 UTC.
The cash path
Deposit order: reentrancy lock, amount check, ceiling check, transferFrom, mint, unlock. Withdraw order: reentrancy lock, amount check, balance check, FXRP-cash check, burn, transfer, unlock. A failed FXRP transfer reverts TransferFailed and rolls the burn back. We did not find a path that burns the receipt and leaves the FXRP behind.
The predicate that stops deposits is P-Cap against maxAssets, 10,000,000.000000 FXRP. We did not discharge a dollar constant as if it were an opcode.
Public desk
We walked myxrp.fi as a stranger: connect, read the deposit panel, add the receipt to a wallet, open explorer-verify, fetch https://myxrp.fi/token.json. The UI binds this bridge. Official name on the record is myXRP. The panel’s room line is room() on this contract.
Out of scope for the predicates above: cabinet snapshot credits, off-chain key custody of holders, FAssets agent economics. Those do not change the 1:1 math.
Notes
KF-N1 — constants for the name. name() and symbol() are the literal myXRP. A search for XRP on the XRP Ledger does not return this receipt. Informational. Accepted. No patch: the strings are not setters.
KF-N2 — cash is checked before the burn. withdraw reads the FXRP balance, then burns, then pushes. A failed push reverts TransferFailed and the burn does not stay. Informational. Accepted. The order is the property; we are not asking for a second path.
Results
Properties P-Bind through P-StuckGift hold. No critical, high, medium, or low finding remains open. Protocol Defence classifies the live bridge and the public desk as a reading of the published bytecode. Counterparties who need a sealed Flare FXRP receipt can treat the deployment at the address above and myxrp.fi as the deployment that was read.