Skip to content

Lending example with Oracle challenge window - #22

Draft
stringhandler wants to merge 9 commits into
mainfrom
st-oracle-lending
Draft

stringhandler wants to merge 9 commits into
mainfrom
st-oracle-lending

Conversation

@stringhandler

Copy link
Copy Markdown
Owner

No description provided.

The node rejects a program that may cost more than its witness's size buys,
with "Program's execution cost could exceed budget". run still built,
signed and even exported such a transaction. Finalizing a covenant input on
Elements now checks the budget, and says how many bytes short the witness is.

Liquid doesn't relay the annex that would pad it (bad-witness-nonstandard),
so the error says to pad with a witness the program reads.
An explicit wallet UTXO, such as a payout a covenant made with
confidential: false, reaches the builder as a covenant input, and the builder
counted only the L-BTC of covenant inputs toward balance and change. Spending
explicit tUSDT therefore built a transaction with no tUSDT change and no
error, which the node refused: bad-txns-in-ne-out.

Every input's amount now counts toward its asset's balance, so the surplus
becomes change where the manifest permits it and an error where it doesn't.
An action's lock_time, {"height": <expr>} or {"time": <expr>}, sets the
transaction's nLockTime, which the check_lock_height and check_lock_time jets
read. Until now it was always zero, so a covenant could only demand a lock
time the wallet could never set.

A height must be below 500,000,000 and a time at least that, since consensus
tells them apart by size. A lock time is ignored when every input is final, so
each input that asks for no sequence gets 0xfffffffe, on both chains.
An example can ship a second manifest in a subdirectory, since run writes
its state files beside each manifest. The parse, validate, schema,
UI-coverage and CLI checks now cover those too.
Burns testnet L-BTC for a new tUSDT asset at the price in a signed oracle
statement. Simplicity can't tell whether a statement is current, so a mint
takes two steps: a request opens a 5-block window in which anyone holding a
newer statement whose price differs by more than 0.5% can cancel it, and
after which anyone can finalize it.

Statements use Mycelia Signal's canonical format and ECDSA scheme, signed by
a local test key (fake_oracle.py), and the covenant verifies and parses them
itself. issue_usdt/ issues the asset. Both paths ran on Liquid testnet; the
README lists the transactions.
The service no longer fixes an oracle key. It fixes a cold key, which signs
BIP340 certificates saying an oracle key may sign statements timestamped
within a range; each statement is presented with its key's certificate, and
the covenant checks both signatures and the range. A new or rotated oracle
needs a new certificate rather than a redeploy, and the cold key can be a
MuSig2 or FROST committee without changing the program.

fake_oracle.py gains cold-keygen, certify and verify-cert, with a BIP340
signer after the BIP's reference code, and the tests check its certificates
against the program's own BIP340 check.

Every address changes, so the README's testnet run is gone until the next
one.
A certificate's range alone doesn't stop a leaked oracle key: it could date a
request at the end of the range, weeks ahead, where no honest statement is
newer and nothing can challenge it before it finalizes.

A request now sets a lock time of timestamp - MAX_FUTURE_SECONDS, which the
covenant checks with check_lock_time. Consensus only mines it once the
chain's median time is past that, so a statement can be dated at most
MAX_FUTURE_SECONDS (default 300) ahead of the chain. On Liquid, whose median
time lags about 5 minutes, an honest request is usable within a minute.

Ran on Liquid testnet: an honest mint, a stale price challenged, a second
oracle certified after deployment challenging the first's request, and a
statement dated an hour ahead refused by the node as non-final.
lending_v3 liquidates only on expiry. Before then, the lender can now start a
liquidation with a certified oracle statement at which the debt is more than
LIQUIDATION_LTV_BPS (default 80%) of the collateral's value. The loan moves to
a pending state recording the claim. Anyone with a newer statement at which
it isn't liquidatable can cancel it back to active; after WINDOW_BLOCKS the
lender burns the lender NFT and takes the collateral. The borrower can repay
in full while it is pending.

The new paths sit behind a separate LIQUIDATION witness, so lending_v3's PATH
values and the offer and active addresses' derivation are unchanged. The
statement, certificate and lock-time checks are oracle_demo's.

Ran on Liquid testnet: a liquidation started at 60000.00 and cancelled at
84231.50, then one started at 59000.00 and finished after the window.
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