04 · 5 min read
Fees and guarantees
A gift that arrives smaller than it was sent is a broken promise. This page is the arithmetic behind the one guarantee YieldLinks makes, and every figure in it was measured on Hedera testnet.
01The rule#
The sender pays every cost; the recipient gets at least the gift. Send 5 SAUCE and the recipient receives at least 5 SAUCE, plus yield if the policy gives it to them.
Two mechanisms make that true, and the tests hold them to it:
| Cost | Paid by | How |
|---|---|---|
| Rounding in share and pool maths | Sender | A 10-unit rounding reserve on top of the gift |
| Submitting the claim | Sender | The prepaid network fee, sent with createLink |
| Creating the recipient's account | Sender | The same prepaid fee |
test/Guarantees.t.sol fuzzes it: RecipientReceivesAtLeastTheAmountTest tries random amounts and checks the recipient never ends up below the gift.
02The rounding reserve#
Shares round down when minted and the Infinity Pool rounds on enter and leave, so a link can come out a unit or two short of what went in. createLink therefore takes amount + ROUNDING_DUST, where ROUNDING_DUST = 10:
gift 5.000000 SAUCE
reserve 0.000010 SAUCE (10 base units, 6 decimals)
approved 5.000010 SAUCETwo other guards back it up. A link's value is capped at what the pool actually holds, so a claim never asks for more than exists, and the source tolerates a shortfall of at most 2 units when one link pays twice (recipient, then yield). Fuzzing found both cases before testnet did.
03The prepaid network fee#
The sender attaches 1.5 HBAR to createLink. The contract stores it with the link and hands it over when the link closes:
| Outcome | The fee goes to |
|---|---|
| Claimed | Whoever submitted the claim, normally the relayer |
| Cancelled or expired | Back to the sender, with the tokens |
The relayer refuses any link that prepaid less than MIN_PREPAID_FEE_TINYBAR = 1.35 HBAR, before it spends anything, with HTTP 402 FeeNotPrepaid. So a link that cannot reimburse it never costs it HBAR.
04What a claim costs#
Measured on testnet on 3 October 2026, at about $0.105 per HBAR:
| Step | HBAR | Paid from |
|---|---|---|
| Create the recipient's account (generated wallet) | 0.58 | Relayer, includes the 0.1 HBAR welcome balance |
| Submit the claim | 0.74 | Relayer |
| Total | 1.32 | Reimbursed from the 1.5 HBAR prepaid |
A claim to an existing wallet or a pasted address skips the account step and costs only the claim. The sender also pays for their own approve and createLink transactions, from their wallet, like any transaction.
05Tinybar and weibar#
The same HBAR has two units depending on where you read it:
| Where | Unit | Decimals | 1.5 HBAR is |
|---|---|---|---|
| Inside the EVM: msg.value, the stored fee | tinybar | 8 | 150_000_000 |
| Over JSON-RPC: ethers, viem, wallets | weibar | 18 | 1_500_000_000_000_000_000 |
// Sending: weibar goes in, the relay divides by 1e10.
await writeLinks({ functionName: "createLink", args, value: parseEther("1.5") });
// Reading it back from the contract: tinybar comes out.
const link = await links.read.links([linkKey]);
const feeHbar = Number(link[8]) / 1e8; // 1.506When a fee cannot be paid#
The fee is sent with a low-level call. If the recipient of the fee cannot accept HBAR (a contract with no receive), the claim or refund still goes through and the fee is credited to the link's sender in pendingFees.
links.withdrawPendingFees(payable(to)); // any address the sender choosesNothing gets stuck, and a hostile submitter cannot block a claim by refusing its own fee.