Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions CHIPs/chip-0052.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
CHIP Number | 0052
:-------------|:----
Title | Partial Offers
Description | Offers that can be partially filled.
Author | [Yak](https://github.com/yakuhito)
Editor | [Dan Perry](https://github.com/danieljperry)
Comments-URI | [CHIPs repo, PR #174](https://github.com/Chia-Network/chips/pull/174)
Status | Review
Category | Informational
Sub-Category | Chialisp
Created | 2025-09-22
Requires | -
Replaces | -
Superseded-By | -

## Abstract
Currently, Chia offers can only be completely filled. If someone makes a 1000 XCH for 2 MRMT offer, a potential taker with 1 MRMT cannot use the offer to get 500 XCH. The current, minimalistic design leads to greater flexibility, as any side of the offer can contain multiple assets, and many asset types are supported out of the box, such as NFTs and revocable CATs (rCATs). This CHIP proposes a new puzzle that enables a different offer type, where each side only has one asset (XCH/CAT/rCAT), but partial fulfillment is possible.

## Motivation
Overall, the current offer standard covers most peer-to-peer trading needs. When considering asset-asset trades (where an asset is XCH, a CAT, or a revocable CAT), they enable an orderbook-like experience, where no transaction is needed to create an offer. The ‘ASSERT_BEFORE_SECONDS_ABSOLUTE’ condition allows offers to only be valid for a certain amount of time before becoming invalid (expiring). The spends are only included in the Chia blockchain once another party - a taker - accepts the offer (settles the trade).

However, when looking more closely at asset-asset trades, makers face a difficult choice. Selling assets in only one offer means traders interested in a smaller amount of the offered asset will ignore the offer in most cases. Selling the asset in multiple chunks over many offers solves this problem, but introduces two new ones. First, the overall blockchain cost (and thus blockchain fees paid by the taker) will significantly increase, as more coin spends will be needed. Second, the coinset model makes it difficult to make two offers use the same coin - the coin either needs to be split (which introduces another transaction, which this time needs to be made by the maker without the guarantee that someone will accept the offer) or its value needs to be used entirely, limiting the effectiveness of the ‘multiple offers’ approach.

To enable a truly orderbook-like experience, something that keeps the advantages of current offers while allowing partial fills is needed.

## Backwards Compatibility
This proposal does not introduce any breaking changes.

## Rationale
Partial offers aim to maintain the advantages of the current offer standard, namely:
* **Support for multiple assets**: The partial offer puzzle allows trading of the three currently available fungible asset (XCH, CATs, revocable CATs), with the option of easily adding new standards in the future by specifying a ‘CAT maker.’
* **Off-chain cancellation**: Partial offers can have an arbitrary set of ‘persistent conditions’ that are outputted each time the offer (or part of it) is filled. This enables expiring partial offers via the ‘ASSERT_BEFORE_SECONDS_ABSOLUTE’ condition, as well as a layer of DoS protection via the ‘RESERVE_FEE’ condition, which requires each fill to pay a minimum blockchain fee.
* **On-chain cancellation**: Currently, offers can be cancelled by their maker before the expiration by making a blockchain transaction that spends one or more of the source coins. Because partial offers might’ve been spent several times before (to be partially filled), the maker of a partial offer may cancel it by spending the latest coin, which contain's the maker's puzzle hash in a 1-of-n configuration.

## Specification
Partial offers are powered by a new puzzle which:
* Asserts the taker pays the required asset to the partial offer maker.
* Calculates the amount of assets the receiver is entitled to, and creates a new partial coin with the remaining amount.
* Outputs a set of ‘persistent’ conditions. This set may include a `RESERVE_FEE` condition (forcing takers to pay a minimum fee for each fill) or an `ASSERT_BEFORE_SECONDS_ABSOLUTE` condition (allowing the offer to expire).
* Optionally, allows the taker to create a coin. This removes the need of the taker to absorb the given asset value in another one of their coins, which, in the case of CATs, needs to be a CAT with the same asset id. This also enables the taker to use normal offers to accept partial ones.

To enable clawbacks, the partial puzzle is wrapped in a 1-of-n puzzle, with the other path being the maker’s puzzle. This allows the maker of the partial offer to spend the latest coin as their own at any time, effectively cancelling the latest partial offer (the original might’ve been partially filled). The current version of partial offers only supports one fungible asset on each side of the trade.

Like normal offers, partial offers can be encoded into a bech32m string with the ‘partial’ prefix. Except for the custom prefix, the same decoding procedure as the one used for offers can be employed to get a spend bundle. The bundle will contain exactly one invalid coin spend, easily recognizable through the coin’s puzzle hash, 0101...01. The partial coin’s puzzle can be constructed by parsing the puzzle of the invalid coin as a partial offer hint (described below). The partial coin’s parent info and amount correspond to the respective parameters of the invalid coin.

The partial hint is defined [here](https://github.com/Yakuhito/partial/blob/master/src/types/partial_hint.rs#L43). An ‘asset info’ type is described [here](https://github.com/Yakuhito/partial/blob/master/src/types/partial_hint.rs#L9). Note that both types are lists, allowing for future extensibility.

To allow wallets to easily discover partial offers that have been accepted at least once solely with on-chain information, the first partial coin should be created with a hint corresponding to the maker's puzzle hash, followed by an 'asset info' struct describing the requested asset. In other words, the memo list of the `CREATE_COIN` that creates the first partial offer coin is `(c maker_puzzle_hash requested_asset_info)`.

The partial offer puzzle can be found [here](https://github.com/Yakuhito/partial/blob/master/puzzles/partial.rue), while its Chialisp equivalent can be found [here](https://github.com/Yakuhito/partial/blob/master/puzzles/partial.clsp).

## Test Cases

The following types of partial offers (partial/full trades and clawbacks) are tested in chia-wallet-sdk: XCH-to-CAT, CAT-to-XCH, CAT-to-CAT, XCH-to-rCAT, rCAT-to-XCH, rCAT-to-CAT, CAT-to-rCAT, rCAT-to-rCAT.

## Reference Implementation
The reference implementation can be found [here](https://github.com/Yakuhito/partial). It includes puzzles and a CLI for creating, viewing, accepting, and cancelling partial offers using the Sage RPC and Coinset[.]org.

Note that partial offer drivers and tests have been integrated into chia-wallet-sdk.


## Security
Because the partial offer puzzle controls outstanding funds until the offer is fully filled or cancelled, puzzle risk is a significant concern. Multiple members of the Chia community have reviewed the puzzle included in this CHIP.

Another concern is that someone may fill a partial offers many times with very small amounts of assets. Under fee pressure conditions, the maker may have to pay a non-zero amount in transaction fees to combine the coins in order to be able to use them. The proposed puzzle offers two protections against the attack. First, the maker may specify a minimum amount of the other asset that's required to spend the partial offer coin. Second, the maker may set a required minimum fee that needs to be paid by the accepting party for every fill.

Partial offers are the first standard to use [Rue](https://github.com/xch-dev/rue)-produced CLVM output. While the compiler has numerous tests, the correspondence between Rue code and CLVM output may still lead to unexpected behavior. This CHIP provides the functionally equivalent Chialisp puzzle, with the diff between the CLVM outputs being manually reviewed by Rue's creator.

## Copyright
Copyright and related rights to this CHIP waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).