> For the complete documentation index, see [llms.txt](/llms.txt)

# Purchasing from a kiosk

Purchase items from kiosks with automatic transfer policy rule resolution.



One of the base functionalities of the SDK is a seamless purchasing flow, allowing for ease of rules
resolving (hiding away the calls). The SDK supports all four rules by default, and works for
`TESTNET` and `MAINNET`. For other networks, see the
[kiosk extension setup section](../introduction) of the introduction.

## How to purchase

By default, the SDK places the item in the caller's kiosk, unless there's a lock rule, in which case
it locks it.

Then following is an example of a purchase call.

```typescript
const item = {
	itemType: '0x..::hero::Hero',
	itemId: '0x..',
	price: 100000n,
	sellerKiosk: '0xSellerKiosk',
};

const tx = new Transaction();
const kioskTx = new KioskTransaction({ transaction: tx, kioskClient: client.kiosk, cap });

await kioskTx.purchaseAndResolve({
	itemType: item.itemType,
	itemId: item.itemId,
	price: item.price,
	sellerKiosk: item.sellerKiosk,
});

kioskTx.finalize();

// Sign and execute transaction.
await signAndExecuteTransaction({ tx: tx });
```

> The function queries for a TransferPolicy for that item, and if a policy is found, it
> automatically resolves all the rules, one by one. You can add a custom rule resolver to the kiosk
> extension, with instructions on how to resolve a custom rule. Read more in the next section.

## Supporting a custom rule

You can use the `purchaseAndResolve` function to support a custom rule.

```typescript
// Assuming client is set up with .$extend(kiosk())
const myCustomRule = {
	rule: `0xMyRuleAddress::game_rule::Rule`,
	packageId: `0xMyRuleAddress`,
	// The resolving function. This is called when calling the `purchaseAndResolve`.
	resolveRuleFunction: (params: RuleResolvingParams) => {
		// By knowing the params we have here, we can extract the variables we need to resolve this rule.
		const { transaction, itemType, packageId, extraArgs, transferRequest } = params;
		const { gamePass } = extraArgs;
		if (!gamePass) throw new Error('GamePass not supplied');

		// Calls the game's rule prove function, which could, for example
		// allow rules to resolve only if the holder has a gamePass object.
		transaction.moveCall({
			target: `${packageId}::game_rule::prove_pass`,
			typeArguments: [itemType],
			arguments: [transferRequest, transaction.object(gamePass)],
		});
	},
};
// This allows rules resolution from the `purchaseAndResolve` function.
client.kiosk.addRuleResolver(myCustomRule);

// Assume `cap` is obtained from client.kiosk.getOwnedKiosks()
const tx = new Transaction();
const kioskTx = new KioskTransaction({ transaction: tx, kioskClient: client.kiosk, cap });

await kioskTx.purchaseAndResolve({
	itemType: item.itemType,
	itemId: item.itemId,
	price: item.price,
	sellerKiosk: item.sellerKiosk,
	extraArgs: {
		gamePass: '0xMyGamePassObjectId',
	},
});

kioskTx.finalize();

// Sign and execute transaction.
await signAndExecuteTransaction({ tx: tx });
```

```typescript
// For reference, here's the RuleResolvingParams contents.
type RuleResolvingParams = {
	transaction: Transaction;
	itemType: string;
	itemId: string;
	price: string;
	policyId: ObjectArgument;
	sellerKiosk: ObjectArgument;
	kiosk: ObjectArgument;
	kioskCap: ObjectArgument;
	transferRequest: TransactionObjectArgument;
	purchasedItem: TransactionObjectArgument;
	packageId: string;
	extraArgs: Record<string, any>; // extraParams contains more possible {key, values} to pass for custom rules.
	kioskClient: KioskClient; // This is the client.kiosk extension
};
```
