From da6184175c7a0f0b5d76d633dbd510c8f5f3060a Mon Sep 17 00:00:00 2001 From: kevin Heifner Date: Tue, 10 Nov 2026 12:57:15 -0600 Subject: [PATCH 1/2] Bill sysio.bond bonds rows to the sysio RAM pool An underwriter's `bonds` row was the one depot row a batch operator paid RAM for. It exists only against locked bond tokens, at most one per underwriter per request, so the `sysio` pool carries it. An issuer's `requests` and `escrows` rows stay issuer-paid. Change-Id: I4ec67c7cc24ee2f1c73a4be52ffa0d7273b174c8 --- .../include/sysio.bond/sysio.bond.hpp | 10 +++++----- contracts/sysio.bond/src/sysio.bond.cpp | 12 +++++++----- contracts/sysio.bond/sysio.bond.wasm | Bin 51332 -> 51325 bytes contracts/tests/sysio.bond_tests.cpp | 17 +++++++++-------- docs/sysio-bond-integration.md | 11 ++++++----- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/contracts/sysio.bond/include/sysio.bond/sysio.bond.hpp b/contracts/sysio.bond/include/sysio.bond/sysio.bond.hpp index e699091444..dbafd938f3 100644 --- a/contracts/sysio.bond/include/sysio.bond/sysio.bond.hpp +++ b/contracts/sysio.bond/include/sysio.bond/sysio.bond.hpp @@ -20,11 +20,11 @@ * transfer into this contract. * * Privileged: an action signed by an account pulls that account's tokens by an inline `transfer` - * under its `active` authority. The issuer pays the RAM of its `requests` and `escrows` rows and an - * underwriter that of its `bonds` row -- unless that account is itself privileged: a system contract - * (`sysio.synd` issuing for an envelope) has no RAM quota of its own, so its rows bill the `sysio` RAM - * pool instead. Later writes by other signers keep the row's payer. The contract's own singletons and - * yield pools bill the `sysio` RAM pool. + * under its `active` authority. The issuer pays the RAM of its `requests` and `escrows` rows -- + * unless it is itself privileged: a system contract (`sysio.synd` issuing for an envelope) has no RAM + * quota of its own, so its rows bill the `sysio` RAM pool instead. Later writes by other signers keep + * the row's payer. Every `bonds` row, the contract's own singletons and the yield pools bill the + * `sysio` RAM pool, so an underwriter needs no RAM. */ #include diff --git a/contracts/sysio.bond/src/sysio.bond.cpp b/contracts/sysio.bond/src/sysio.bond.cpp index 9cd92abfb1..e26a92289f 100644 --- a/contracts/sysio.bond/src/sysio.bond.cpp +++ b/contracts/sysio.bond/src/sysio.bond.cpp @@ -37,9 +37,11 @@ namespace custody = opp::shadow::custody; // The contract's own rows -- `bondconfig`, `bondcounters`, `yieldpool` -- bill the sysio RAM pool, // not this contract account (privileged-contract model, as sysio.opreg uses): the account stays -// finite at code+abi size. A request's rows bill the account that created them (`payer_for`): the -// issuer its `requests` and `escrows` rows, an underwriter its `bonds` row. Later writes by any signer -// keep the row's payer (`same_payer`), which a privileged contract may do. +// finite at code+abi size. So does a `bonds` row: it exists only against locked bond tokens, at most +// one per underwriter per request, so an underwriter needs no RAM of its own. An issuer's `requests` +// and `escrows` rows bill the issuer (`payer_for`): anyone may open a request, with a statement of +// its own size. Later writes by any signer keep the row's payer (`same_payer`), which a privileged +// contract may do. constexpr name ram_payer = bond::SYSTEM_ACCOUNT; /// Permission this contract sends its own `sysio.liq::addyield` under. @@ -139,7 +141,7 @@ constexpr uint64_t max_asset_amount = static_cast(asset::max_amount); /// A privileged account is a system contract (`sysio.synd` issuing requests for its envelopes), and a /// system contract has no RAM quota of its own -- it lives on what `sysio.roa` gifts it for its code /// and abi -- so its rows bill the `sysio` RAM pool, as every system contract's own rows do. The ONE -/// place that decides the payer of a request, escrow or bond row. +/// place that decides the payer of a request or escrow row. name payer_for(name account) { return is_privileged(account) ? ram_payer : account; } @@ -442,7 +444,7 @@ void bond::accept(name underwriter, uint64_t request_id, uint64_t amount) { bond_row row = bonds.try_get(key).value_or( bond_row{.request_id = request_id, .underwriter = underwriter, .amount = 0}); credit_holding(row.yield, row.amount, bonded_amount, req->token_code, *custody); - bonds.set(payer_for(underwriter), key, row); + bonds.set(ram_payer, key, row); const bool fully_bonded = bonded_amount == remainder; requests.modify(same_payer, request_key{request_id}, [&](request_row& r) { diff --git a/contracts/sysio.bond/sysio.bond.wasm b/contracts/sysio.bond/sysio.bond.wasm index 3e8d2edf60415da71a567e241c83381c9b23059a..2b97806ad95079d7f770749793f5dc8b9644b847 100755 GIT binary patch delta 28 kcmZpf$ozK#^M)-fj8ivnWzo=LY}|ZLZz delta 35 rcmex6fw^TO^M)-fjB_?`Wzo=L?AUxyZz&TSqXMG Date: Wed, 11 Nov 2026 07:46:16 -0500 Subject: [PATCH 2/2] Test that a privileged underwriter's bond row bills sysio `accept_bills_sysio` covers a non-privileged underwriter; this covers a privileged one, so both cases of "every `bonds` row bills `sysio`" are pinned. Change-Id: I231a947461b2a46f2b533c1b6828ead50fd18b9a --- contracts/tests/sysio.bond_tests.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/contracts/tests/sysio.bond_tests.cpp b/contracts/tests/sysio.bond_tests.cpp index 65fcffb1b6..5c07f1bc36 100644 --- a/contracts/tests/sysio.bond_tests.cpp +++ b/contracts/tests/sysio.bond_tests.cpp @@ -874,6 +874,28 @@ BOOST_FIXTURE_TEST_CASE(accept_bills_sysio, sysio_bond_tester) try { BOOST_REQUIRE_GT(ram_usage(SYSIO_ACCOUNT), sysio_ram); } FC_LOG_AND_RETHROW() +// A privileged underwriter -- a system contract -- has its bond row billed to the sysio RAM pool as +// well: every underwriter's bond row bills the pool, privileged or not. +BOOST_FIXTURE_TEST_CASE(a_privileged_underwriter_bills_sysio, sysio_bond_tester) try { + // sysio.tokens, the token registry, is a privileged system contract of the fixture. + constexpr auto system_contract = TOKENS_ACCOUNT; + BOOST_REQUIRE_EQUAL(success(), transfer_wire(SYSIO_ACCOUNT, system_contract, 100 * UNIT)); + // The bounty opens sysio.bond's own WIRE balance row first, so the accept below writes only the bond row. + BOOST_REQUIRE_EQUAL(success(), request("issuer"_n, "oppenvelope"_n, bytes(32, 'a'), WIRE, 10 * UNIT, 1 * UNIT)); + const auto sysio_ram = ram_usage(SYSIO_ACCOUNT); + const auto issuer_ram = ram_usage("issuer"_n); + const auto underwriter_ram = ram_usage(system_contract); + + BOOST_REQUIRE_EQUAL(success(), accept(system_contract, 1, 10 * UNIT)); + std::string bond_key = request_key_of(1); + append_key_word(bond_key, system_contract.to_uint64_t()); + BOOST_REQUIRE_EQUAL(SYSIO_ACCOUNT, payer_of("bonds"_n, bond_key)); + BOOST_REQUIRE_EQUAL("issuer"_n, payer_of("requests"_n, request_key_of(1))); + BOOST_REQUIRE_EQUAL(underwriter_ram, ram_usage(system_contract)); + BOOST_REQUIRE_EQUAL(issuer_ram, ram_usage("issuer"_n)); + BOOST_REQUIRE_GT(ram_usage(SYSIO_ACCOUNT), sysio_ram); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(accept_in_wire_pulls_wire, sysio_bond_tester) try { BOOST_REQUIRE_EQUAL(success(), request("issuer"_n, "oppenvelope"_n, bytes(32, 'a'), WIRE, 10 * UNIT, 0)); const auto before = wire_balance("alice"_n);