Contractless/docs/LOAN_TRANSACTIONS.md

589 lines
19 KiB
Markdown

# 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 `<Tab>` 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/<hash>.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 <path/to/file.json>
```
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 <loan_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 <wallet_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. |