diff --git a/docs/LOAN_TRANSACTIONS.md b/docs/LOAN_TRANSACTIONS.md new file mode 100644 index 0000000..92a6499 --- /dev/null +++ b/docs/LOAN_TRANSACTIONS.md @@ -0,0 +1,588 @@ +# Loan Transactions + +Contractless loans are native two-party loan contracts. They do not use a smart-contract VM, and they are not simple wallet notes. A confirmed loan contract moves real balances on chain: + +- The lender's loan asset moves to the borrower. +- The borrower's collateral moves into a chain-tracked collateral holding balance. +- Later loan payments move repayment value back to the lender. +- A collateral claim closes the contract by moving the collateral either back to the borrower or to the lender. + +Loans are one of the most unique transaction categories in Contractless. This guide explains how the loan contract, loan payment, and collateral claim transactions work together. + +On Windows, add `.exe` to each command name. + +When a tool asks for a wallet path or transaction file path, press `` to search and auto-complete files and folders. + +## CLI Tools + +| Tool | Purpose | +| --- | --- | +| `create_loan_tx` | Creates the lender-signed loan offer. | +| `verify_sign_loan_tx` | Lets the borrower review terms, second-sign the loan, and save the completed contract. | +| `create_loan_payment_tx` | Creates a borrower payment transaction for an active loan. | +| `create_collateral_claim_tx` | Creates a collateral claim transaction. Used by either borrower or lender depending on contract state. | +| `lookup_loan_by_address` | Lists loan contracts involving a wallet address. | +| `lookup_loan_by_hash` | Looks up one loan contract by contract hash. | + +Creation tools save signed transaction JSON under: + +```text +./transactions/.json +``` + +Saving a transaction file does not broadcast it. Submit completed transactions with `broadcast_transaction` or with the GUI wallet import/broadcast flow. + +## Three Transaction Types + +Loans use three native transaction types: + +| Transaction | Type | Who Signs | What It Does | +| --- | ---: | --- | --- | +| Loan contract | `7` | Lender and borrower | Creates the loan, disburses the loaned asset, and locks collateral. | +| Loan payment | `8` | Borrower | Pays some or all of the scheduled repayment balance. | +| Collateral claim | `9` | Borrower or lender | Returns collateral to borrower after full repayment, or transfers collateral to lender when claim rules are met. | + +## Loan Lifecycle + +1. The lender creates a loan offer with `create_loan_tx`. +2. The lender sends the saved JSON file to the borrower. +3. The borrower reviews and signs the loan with `verify_sign_loan_tx`. +4. The completed loan contract is broadcast. +5. When the loan confirms, the loaned asset moves from lender to borrower. +6. At the same time, collateral moves from borrower to a collateral holding balance. +7. The borrower makes one or more payments with `create_loan_payment_tx`. +8. When fully paid, the borrower uses `create_collateral_claim_tx` to reclaim collateral. +9. If the borrower becomes delinquent enough, the lender uses `create_collateral_claim_tx` to claim collateral. + +## Loan Contract Creation + +Use `create_loan_tx` to create the lender side of a loan. + +Usage: + +```text +create_loan_tx +``` + +The active wallet becomes the lender. The output is only partially signed. The borrower must review and sign it before it can be broadcast. + +### Loan Contract Fields + +| Field | Size | Meaning | +| --- | ---: | --- | +| `txtype` | 1 byte | Transaction type. For loan contracts this is `7`. | +| `timestamp` | 4 bytes | Loan start timestamp. Created from the entered start date at UTC midnight. | +| `loan_coin` | 15 bytes | Base coin or token being lent, padded to 15 bytes. | +| `loan_amount` | 8 bytes | Amount lent, in atomic units. | +| `lender` | 22 bytes | Lender short address. | +| `collateral` | 21 bytes | Base coin, token, or numbered NFT collateral field. | +| `collateral_amount` | 8 bytes | Collateral amount in atomic units. For NFT collateral, use `1`. | +| `borrower` | 22 bytes | Borrower short address. | +| `payment_period` | 1 byte | `d`, `w`, or `m` for daily, weekly, or monthly. | +| `payment_number` | 1 byte | Total number of scheduled payments. | +| `payment_amount` | 8 bytes | Amount due per scheduled payment, in atomic units. | +| `grace_period` | 1 byte | Number of overdue payments allowed before normal lender claim can become possible. | +| `max_late_value` | 8 bytes | Overdue value threshold for normal lender collateral claim. | +| `txfee` | 8 bytes | Lender base-currency transaction fee. Minimum is `3` CLC or CLTC. | +| `hash` | 32 bytes | Hash of the unsigned loan contract payload. | +| `signature1` | 666 bytes | Lender signature. | +| `signature2` | 666 bytes | Borrower signature. Present only after borrower signs. | + +### Prompts + +`create_loan_tx` asks for: + +| Prompt | What To Enter | +| --- | --- | +| Loan coin/token | Base coin or existing token being lent. | +| Loan amount | Amount lent in display units. | +| Payment period | `daily`, `weekly`, or `monthly`. | +| Payment number | Number of scheduled payments required. | +| Payment amount | Amount due each payment period. | +| Grace period | How many overdue payments are allowed before normal lender claim can become possible. | +| Max late value | How far behind in value the borrower may be before normal lender claim can become possible. | +| Collateral coin/token/NFT | Base coin, token, or NFT collateral. Numbered NFTs use the `name_#####` form. | +| Collateral amount | Amount of collateral. Enter `1` for NFT collateral. | +| Start date | Loan start date as `YYYY-MM-DD`. Stored as UTC midnight for that date. | +| Wallet path | Lender wallet path. | +| Wallet key | Lender wallet decryption key. | +| Borrower address | Borrower short address or vanity address. | +| Transaction fee | Minimum `3` CLC or CLTC. | + +### Loan Creation Rules + +A loan contract is valid only when: + +- Both lender and borrower addresses are registered and valid. +- Lender and borrower both sign the exact same loan hash. +- The lender has enough of the loan asset to fund the loan. +- The lender has enough base currency for the loan creation fee. +- The borrower has enough collateral. +- The loan asset exists as base currency or a token. +- The collateral exists as base currency, a token, or an NFT. +- `payment_period` is `d`, `w`, or `m`. +- `payment_amount` is not greater than `loan_amount`. +- `payment_amount * payment_number` is at least the `loan_amount`. +- `max_late_value` is not greater than `loan_amount`. +- `grace_period` is not greater than `payment_number`. +- The contract is broadcast within 30 days of the stored timestamp. + +### What Happens When The Loan Confirms + +When a valid loan contract is mined: + +- The lender pays the base-currency fee to the miner. +- The loaned asset moves from lender to borrower. +- The collateral moves from borrower to a collateral holding balance named from the contract hash. +- The contract is indexed for both lender and borrower. +- The loan is marked active. + +The collateral is not held by the lender while the loan is active. It is held by the chain under a derived collateral holding balance. + +## Borrower Review And Second Signature + +The borrower signs the lender-created file with `verify_sign_loan_tx`. + +Usage: + +```text +verify_sign_loan_tx +``` + +The tool: + +1. Loads the lender-signed loan JSON. +2. Loads the borrower wallet. +3. Confirms the active wallet is the borrower in the contract. +4. Rebuilds the loan hash from the JSON fields. +5. Shows the borrower human-readable questions about the loan terms. +6. Signs only if the rebuilt hash matches the lender's hash. +7. Saves the completed two-signature loan contract JSON. + +The borrower is asked to confirm: + +- Amount and asset they expect to receive. +- Collateral amount and asset they agree to lock. +- Payment period. +- Total number of payments. +- Amount of each payment. +- Grace period. +- Max late value. +- Start date. +- Lender wallet address. + +After borrower signing, the output contains both `signature1` and `signature2` and can be broadcast. + +## Payment Schedule + +Loan schedules are based on the loan `timestamp`, which is created from the start date at UTC midnight. + +Payment periods: + +| Code | Meaning | First Payment Due | +| --- | --- | --- | +| `d` | Daily | 1 day after start date | +| `w` | Weekly | 7 days after start date | +| `m` | Monthly | 1 calendar month after start date | + +A payment is not overdue until the full due date has passed in UTC. + +Example: + +```text +Start date: March 15 +Period: daily +First payment due: March 16 +First payment overdue: March 17 at 00:00 UTC +``` + +Weekly works the same way, but with 7-day intervals. + +Monthly payments are anchored to the original calendar day. If a month does not have that day, the due date uses the last day of that month. + +Example: + +```text +Start date: January 31 +First monthly due date: February 28, or February 29 in a leap year +Second monthly due date: March 31 +``` + +## Loan Payments + +Use `create_loan_payment_tx` to create a borrower payment. + +Usage: + +```text +create_loan_payment_tx +``` + +The transaction type is `8`. + +### Loan Payment Fields + +| Field | Size | Meaning | +| --- | ---: | --- | +| `txtype` | 1 byte | Transaction type. For loan payments this is `8`. | +| `timestamp` | 4 bytes | Payment creation timestamp. | +| `payback_amount` | 8 bytes | Amount paid toward the contract, in the loan asset atomic units. | +| `contract_hash` | 32 bytes | Hash of the loan contract being paid. | +| `address` | 22 bytes | Payer short address. | +| `tip` | 8 bytes | Miner tip paid in the loan asset. Must be at least 1% of payment amount. | +| `txfee` | 8 bytes | Base-currency transaction fee. Minimum is `0.01` CLC or CLTC. | +| `hash` | 32 bytes | Hash of the payment transaction. | +| `signature` | 666 bytes | Payer signature. | + +### Payment Prompts + +`create_loan_payment_tx` asks for: + +| Prompt | What To Enter | +| --- | --- | +| Loan contract hash | Contract hash of the loan being paid. | +| Payment amount | Amount paid toward the loan in display units. | +| Miner tip | Tip in the loan asset. Must be at least 1% of payment amount. | +| Fee | Minimum `0.01` CLC or CLTC. | +| Wallet path | Borrower wallet path. | +| Wallet key | Borrower wallet decryption key. | + +### Payment Rules + +Payments are flexible: + +- The borrower may make partial payments. +- The borrower may pay more than one scheduled payment at once. +- The borrower may pay the full remaining balance early. + +But payments cannot exceed the remaining contract balance. The node also checks pending loan payments in the mempool so multiple pending payments cannot collectively overpay the loan. + +Payment totals are tracked by value, not by "number of payment transactions." + +Example: + +```text +Scheduled payment amount: 210 +Borrower sends five payments of 1 +Total paid: 5 +Completed scheduled payment value: 5 of 210 +``` + +Those five small payments do not count as five full scheduled payments. They only reduce the overdue value by `5`. + +When a payment confirms: + +- The borrower pays the base-currency fee to the miner. +- The borrower pays `payback_amount` of the loan asset to the lender. +- The borrower pays `tip` of the loan asset to the miner. +- The payment amount is appended to the contract payment history. + +## Collateral Claims + +Use `create_collateral_claim_tx` to create a collateral claim. + +Usage: + +```text +create_collateral_claim_tx +``` + +The transaction type is `9`. + +The same transaction type is used by: + +- Borrower reclaiming collateral after full repayment. +- Lender claiming collateral after the borrower is sufficiently delinquent. + +### Collateral Claim Fields + +| Field | Size | Meaning | +| --- | ---: | --- | +| `txtype` | 1 byte | Transaction type. For collateral claims this is `9`. | +| `time` / `timestamp` | 4 bytes | Claim creation timestamp. | +| `contract_hash` | 32 bytes | Hash of the loan contract. | +| `address` | 22 bytes | Claimant short address. Must be lender or borrower. | +| `txfee` | 8 bytes | Base-currency transaction fee. Minimum is `3` CLC or CLTC. | +| `signature` | 666 bytes | Claimant signature. | + +### Claim Prompts + +`create_collateral_claim_tx` asks for: + +| Prompt | What To Enter | +| --- | --- | +| Loan contract hash | Contract hash of the loan being claimed. | +| Fee | Minimum `3` CLC or CLTC. | +| Wallet path | Claimant wallet path. | +| Wallet key | Claimant wallet decryption key. | + +Only the lender or borrower can claim collateral. + +## Borrower Collateral Reclaim + +The borrower can reclaim collateral only after the loan is fully paid. + +The full repayment requirement is: + +```text +payment_amount * payment_number +``` + +The borrower cannot reclaim collateral while any part of that scheduled total remains unpaid. + +When borrower reclaim confirms: + +- The borrower pays the base-currency collateral claim fee to the miner. +- Collateral moves from the collateral holding balance back to the borrower. +- The loan is marked inactive. + +## Lender Collateral Claim + +Lender collateral claims have two normal conditions: + +1. The borrower must be past the allowed missed-payment grace period. +2. The overdue value must be greater than `max_late_value`. + +Both normal conditions must be met. One condition alone is not enough. + +### Condition 1: Grace Period + +The node calculates how many scheduled payments are overdue as of the claim time. + +A payment only becomes overdue after the full UTC due date has passed. + +The lender cannot claim while: + +```text +payments_due <= grace_period +``` + +The normal grace condition is met only when: + +```text +payments_due > grace_period +``` + +Example: + +```text +grace_period = 1 +payments_due = 1 +claim rejected + +grace_period = 1 +payments_due = 2 +grace condition met +``` + +### Condition 2: Overdue Value + +The node calculates: + +```text +should_have_paid = payments_due * payment_amount +overdue_value = should_have_paid - total_paid +``` + +The normal overdue-value condition is met only when: + +```text +overdue_value > max_late_value +``` + +Equal is not enough. + +Example: + +```text +max_late_value = 210 +overdue_value = 210 +claim rejected + +max_late_value = 210 +overdue_value = 211 +claim allowed if grace condition is also met +``` + +This prevents collateral from being claimed merely because a scheduled due date passed. The borrower must be both late enough in time and behind enough in value. + +### Partial Payment Example + +Assume: + +```text +payment_amount = 210 +grace_period = 1 +max_late_value = 210 +``` + +If the borrower sends five payments of `1`, total paid is `5`. + +After the first payment is overdue: + +```text +payments_due = 1 +should_have_paid = 210 +total_paid = 5 +overdue_value = 205 +``` + +The claim is rejected because: + +- `payments_due <= grace_period` +- `overdue_value <= max_late_value` + +After the second payment is overdue: + +```text +payments_due = 2 +should_have_paid = 420 +total_paid = 5 +overdue_value = 415 +``` + +The claim can be allowed because: + +- `payments_due > grace_period` +- `overdue_value > max_late_value` + +## Final Term Plus Grace Rule + +There is one special final closeout rule. + +After the full loan term plus the allowed grace period has passed, any unpaid remaining balance allows the lender to claim collateral. + +This rule exists to prevent a borrower from leaving a small final balance unpaid forever. + +Example: + +```text +payment_amount = 100 +payment_number = 5 +grace_period = 1 +max_late_value = 100 +remaining_balance = 99 +``` + +Under the normal overdue-value rule, `99` is not greater than `100`, so the lender might never be able to claim collateral. + +The final closeout rule fixes that: + +```text +full loan term + grace period has passed +remaining_balance > 0 +lender can claim collateral +``` + +This final rule still has a time requirement. The lender must wait until the full schedule plus grace period has passed. What it ignores is the normal `max_late_value` threshold, because any unpaid amount after the final grace window means the loan was not fully repaid. + +## Lookup By Hash + +Use `lookup_loan_by_hash` to inspect one loan contract. + +Usage: + +```text +lookup_loan_by_hash +``` + +The tool asks for a wallet path and wallet key for authenticated RPC handshake. The lookup does not spend funds. + +Expected output includes: + +```json +{ + "contract": "loan_contract_hash", + "status": "active", + "creation_date": "06-30-26", + "start_timestamp": 1782777600, + "lender": "lender_short_address.cltc", + "borrower": "borrower_short_address.cltc", + "coin_loaned": "CLTC", + "loaned_count": 1000.0, + "loaned_count_atomic": 100000000000, + "collateral": "tokenname", + "collateral_count": 2000.0, + "collateral_count_atomic": 200000000000, + "payment_type": "daily", + "number_of_payments": 5, + "payment_value": 210.0, + "payment_value_atomic": 21000000000, + "max_late_payments": 1, + "max_late_value": 210.0, + "max_late_value_atomic": 21000000000, + "total_payments_made": 1, + "total_value_paid": 210.0, + "total_value_paid_atomic": 21000000000, + "pending_value": 0.0, + "pending_value_atomic": 0, + "remaining_balance": 840.0, + "remaining_balance_atomic": 84000000000, + "remaining_after_pending": 840.0, + "remaining_after_pending_atomic": 84000000000, + "collateral_claimed_by": "", + "payments": [ + { + "txid": "payment_txid", + "amount": 210.0, + "payee": "borrower_short_address.cltc", + "date": "07-01-26" + } + ] +} +``` + +Statuses: + +| Status | Meaning | +| --- | --- | +| `active` | Loan is active and not currently delinquent by due schedule. | +| `delinquent` | Scheduled expected payments exceed confirmed paid value. | +| `inactive` | Collateral has been claimed or returned. | + +`pending_value` is the total of pending mempool payments known to the node. It is shown for wallet/user awareness, but consensus validation of blocks uses confirmed payment history. + +In the payment history, `payee` is the field name returned by the current lookup parser for the payment transaction address. In normal borrower payments, this is the borrower/payer address from the payment transaction. + +## Lookup By Address + +Use `lookup_loan_by_address` to list loan contracts involving a wallet address. + +Usage: + +```text +lookup_loan_by_address +``` + +The address can be a short address or vanity address. The tool asks for a wallet path and wallet key for authenticated RPC handshake. The lookup does not spend funds. + +Expected output: + +```json +{ + "address": "wallet_short_address.cltc", + "contracts": 2, + "loans": [ + { + "contract": "loan_contract_hash", + "status": "active", + "lender": "lender_short_address.cltc", + "borrower": "borrower_short_address.cltc", + "payments": [] + } + ] +} +``` + +Each loan entry uses the same summary fields as `lookup_loan_by_hash`. + +## Common Problems + +| Problem | Likely Cause | +| --- | --- | +| Loan contract rejected | Missing second signature, bad hash, invalid asset, insufficient lender balance, insufficient borrower collateral, fee below `3`, bad payment schedule, or broadcast more than 30 days after timestamp. | +| Borrower cannot sign | Active wallet is not the borrower, terms were changed after lender signed, or the borrower rejected one of the review questions. | +| Payment rejected | Contract not active, contract hash is not a loan, payment exceeds remaining balance, pending payments would overpay, tip below 1%, fee below `0.01`, or borrower lacks funds. | +| Borrower collateral reclaim rejected | Loan is not fully paid. | +| Lender collateral claim rejected | Grace period has not passed, overdue value is not greater than `max_late_value`, final closeout window has not passed, collateral already claimed, or fee is below `3`. | +| Lookup returns no loan | The contract is not confirmed, the hash is not a loan contract, or the queried address is not lender or borrower on any indexed contract. |