Docs / Allocation rules
Choose and extend allocation rules
Use single-seller procurement or split fulfillment, and understand exactly what can be customized.
Lowest-price procurement
The default lowest-price-v1 rule selects one seller. Before selection, the SDK rejects offers that cannot fill the complete pool or exceed any buyer’s total cap. The cheapest eligible unit price wins; ASCII seller ID breaks ties. Charges use the selected seller’s quoted price.
Split fulfillment
import { cheapestCapacity, createRound } from "near-swarmkit";
const round = createRound({ ...spec, mechanismId: cheapestCapacity.id });cheapest-capacity-v1 orders buyers by budget per unit, tightest first, then draws inventory from sellers in ascending price order. The result must fill all admitted demand. A null result is no sale. This is a greedy heuristic; failure does not prove that no feasible allocation exists.
A custom winner rule
const mostCapacity = {
id: "capacity-first-v1",
selectWinner(offers) {
return [...offers].sort((a, b) => {
const delta = BigInt(b.capacity) - BigInt(a.capacity);
return delta < 0n ? -1 : delta > 0n ? 1
: a.sellerId < b.sellerId ? -1 : a.sellerId > b.sellerId ? 1 : 0;
})[0]?.sellerId ?? null;
},
};
const round = createRound({ ...spec, mechanismId: mostCapacity.id }, Date.now, mostCapacity);
A custom split rule
Implement allocate(buyers, offers) instead of selectWinner. Return null or an array of { buyerId, sellerId, quantity }. Each buyer–seller pair must be unique. The SDK computes amounts at the revealed bid prices, verifies every buyer is filled exactly, and rejects over-budget or over-capacity results. It does not accept custom payment prices through this interface.
Keep replay deterministic
Give each implementation a versioned ID and supply the same implementation to createRound, replayRound, resumeRound, settlementPlanFromTranscript and auditSettlement. Never silently change an implementation behind an old ID. Avoid wall clocks, random tie-breaking or network calls inside allocation functions.
Inspect the decision
const decision = explainAllocation(round.snapshot());
console.log(decision.reason);
console.table(decision.buyers); // spend, unused budget, fulfillment lines
console.table(decision.sellers); // allocation or rejection reasonCall this only on a closed round. “Not selected by mechanism” does not imply a bid was invalid. The explanation reports the recorded outcome without pretending to expose the internal reasoning of arbitrary custom plugins.