Kiosk SDK
Migration from V1

Migrating from Kiosk SDK V1

The original version of Kiosk SDK V1 provided basic experimentation with the Kiosk API. The new version of the SDK provides a more robust experience for building kiosk/transfer policy transactions.

The new SDK offers a builder-pattern API, which provides better autocomplete capabilities, and also makes code more readable.

While a one-to-one mapping between the old and new SDK is not possible, the following examples should help you get started.

An important benefit of the new SDK is that it works seamlessly with Personal Kiosk, which was not the case with the V1 SDK (you would always have to wrap the transaction with borrow_cap / return_cap calls depending on whether the kiosk is personal or not).

Placing an item to kiosk and listing it for sale

The following example is from the original Kiosk SDK V1 documentation.

V1 implementation

import { placeAndList } from '@mysten/kiosk';
import { TransactionBlock } from '@mysten/sui.js/transactions';
 
const placeAndListToKiosk = async () => {
	const kiosk = 'SomeKioskId';
	const kioskCap = 'KioskCapObjectId';
	const itemType = '0xItemAddr::some:ItemType';
	const item = 'SomeItemId';
	const price = '100000';
 
	const tx = new TransactionBlock();
 
	placeAndList(tx, itemType, kiosk, kioskCap, item, price);
 
	// ... continue to sign and execute the transaction
	// ...
};

V2 implementation

Using the new SDK, you can build the same transaction as follows:

/// You need to do this only once and re-use it in the application.
const kioskClient = new KioskClient({
	client: new SuiClient({
		url: getFullnodeUrl('mainnet'),
	}),
	network: Network.MAINNET,
});
 
const placeAndListToKiosk = async () => {
	// Assume you have saved the user's preferred kiosk Cap somewhere in your app's state.
	const { kioskOwnerCaps } = await kioskClient.getOwnedKiosks({ address: '0xSomeAddress' });
 
	const txb = new TransactionBlock();
 
	// Assume you use the first owned kiosk.
	new KioskTransaction({ transactionBlock: txb, kioskClient, cap: kioskOwnerCaps[0] })
		.placeAndList({
			itemType: '0xItemAddr::some:ItemType',
			item: 'SomeItemId',
			price: '100000',
		})
		.finalize();
 
	// ... continue to sign and execute the transaction
};

Create a new kiosk

The following example is from the original Kiosk SDK V1 documentation.

V1 implementation

import { createKioskAndShare } from '@mysten/kiosk';
import { TransactionBlock } from '@mysten/sui.js/transactions';
 
const createKiosk = async () => {
	const accountAddress = '0xSomeSuiAddress';
 
	const tx = new TransactionBlock();
	const kiosk_cap = createKioskAndShare(tx);
 
	tx.transferObjects([kiosk_cap], tx.pure(accountAddress, 'address'));
 
	// ... continue to sign and execute the transaction
	// ...
};

V2 implementation

Using the new SDK, you can build the same transaction as follows:

/// You need to do this only once and re-use it in the application.
const kioskClient = new KioskClient({
	client: new SuiClient({
		url: getFullnodeUrl('mainnet'),
	}),
	network: Network.MAINNET,
});
 
const placeAndListToKiosk = async () => {
	const txb = new TransactionBlock();
 
	const kioskTx = new KioskTransaction({ transactionBlock: txb, kioskClient });
 
	kioskTx.shareAndTransferCap('0xSomeSuiAddress').finalize();
 
	// ... continue to sign and execute the transaction
};

Purchasing an item and resolving rules

The following example is from the original Kiosk SDK V1 documentation.

V1 implementation

import { queryTransferPolicy, purchaseAndResolvePolicies, place, testnetEnvironment } from '@mysten/kiosk';
import { SuiClient } from '@mysten/sui.js/client';
 
const client = new SuiClient(
  url: 'https://fullnode.testnet.sui.io:443',
);
 
// The kiosk we're purchasing from.
const kioskId = `0xSomeKioskAddress`;
// A sample item retrieved from `fetchKiosk` function (or hard-coded).
const item = {
  isLocked: false,
  objectId: "0xb892d61a9992a10c9453efcdbd14ca9720d7dc1000a2048224209c9e544ed223"
  type: "0x52852c4ba80040395b259c641e70b702426a58990ff73cecf5afd31954429090::test::TestItem",
  listing: {
    isExclusive: false,
    listingId: "0x368b512ff2514dbea814f26ec9a3d41198c00e8ed778099961e9ed22a9f0032b",
    price: "20000000000" // in MIST
  }
}
const ownedKiosk = `0xMyKioskAddress`;
const ownedKioskCap = `0xMyKioskOwnerCap`;
 
const purchaseItem = async (item, kioskId) => {
 
  // Fetch the policy of the item (could be an array, if there's more than one transfer policy)
  const policies = await queryTransferPolicy(client, item.type);
  // Selecting the first one for simplicity.
  const policyId = policy[0]?.id;
  // Initialize tx block.
  const tx = new TransactionBlock();
 
  // Both are required if you there is a `kiosk_lock_rule`.
  // Optional otherwise. Function throws an error if there's a kiosk_lock_rule and these are missing.
  const extraParams = {
    ownedKiosk,
    ownedKioskCap
  }
  // Define the environment.
  // To use a custom package address for rules, you could call:
  // const environment = customEnvironment('<PackageAddress>');
  const environment = testnetEnvironment;
 
  // Extra params. Optional, but required if the user tries to resolve a `kiosk_lock_rule`.
  // Purchases the item. Supports `kiosk_lock_rule`, `royalty_rule` (accepts combination too).
  const result = purchaseAndResolvePolicies(tx, item.type, item.listing.price, kioskId, item.objectId, policy[0], environment, extraParams);
 
  // result = {item: <the_purchased_item>, canTransfer: true/false // depending on whether there was a kiosk lock rule }
  // If the item didn't have a kiosk_lock_rule, you need to do something with it.
  // For example, place it in your own kiosk. (demonstrated below)
  if(result.canTransfer) place(tx, item.type, ownedKiosk, ownedKioskCap , result.item);
 
  // ...finally, sign PTB & execute it.
 
};

V2 implementation

Using the new SDK, you can build the same transaction as follows:

This works with both personal and non-personal kiosks.

/// You need to do this only once and re-use it in the application.
const kioskClient = new KioskClient({
    client: new SuiClient({
        url: getFullnodeUrl('mainnet'),
    }),
    network: Network.MAINNET,
});
 
// An Item as returned from `kioskClient.getKiosk()` call.
const item = {
  isLocked: false,
  objectId: "0xb892d61a9992a10c9453efcdbd14ca9720d7dc1000a2048224209c9e544ed223"
  type: "0x52852c4ba80040395b259c641e70b702426a58990ff73cecf5afd31954429090::test::TestItem",
  kioskId: '0xSomeKioskAddress',
  listing: {
    isExclusive: false,
    listingId: "0x368b512ff2514dbea814f26ec9a3d41198c00e8ed778099961e9ed22a9f0032b",
    price: "20000000000" // in MIST
  }
}
 
const purchase = async () => {
    // Assume you have saved the user's preferred kiosk Cap somewhere in your app's state.
    // You wouldn't need to query this for every purchase.
    const { kioskOwnerCaps } = await kioskClient.getOwnedKiosks({ address: '0xSomeAddress' });
 
    const txb = new TransactionBlock();
 
    const kioskTx = new KioskTransaction({ transactionBlock: txb, kioskClient, cap: kioskOwnerCaps[0] });
 
    // Purchase the item and resolve the rules.
    await kioskTx.purchaseAndResolve({
        itemType: item.type,
        itemId: item.objectId,
        price: item.listing.price,
        sellerKiosk: item.kioskId,
    });
 
    kioskTx.finalize();
};

Attach rules to transfer policy

The following example was taken from the original Kiosk SDK V1 documentation.

V1 implementation

import {
	createTransferPolicy,
	attachKioskLockRule,
	attachRoyaltyRule,
	testnetEnvironment,
	percentageToBasisPoints,
} from '@mysten/kiosk';
import { TransactionBlock } from '@mysten/sui.js/transactions';
 
// Attaches a royalty rule of 1% or 0.1 SUI (whichever is bigger)
// as well as a kiosk lock, making the objects trade-able only from/to a kiosk.
const attachStrongRoyalties = async () => {
	const type = 'SomePackageId::type::MyType'; // the Type for which we're attaching rules.
	const policyId = 'policyObjectId'; // the transfer Policy ID that was created for that Type.
	const transferPolicyCap = 'transferPolicyCapId'; // the transferPolicyCap for that policy.
 
	// Royalties configuration.
	const percentage = 2.55; // 2.55%
	const minAmount = 100_000_000; // 0.1 SUI.
 
	// The environment on which we're referecing the rules package.
	// Use `mainnetEnvironment` for mainnet.
	const enviroment = testnetEnvironment;
 
	const tx = new TransactionBlock();
 
	attachKioskLockRule(tx, type, policyId, policyCapId, enviroment);
	attachRoyaltyRule(
		tx,
		type,
		policyId,
		policyCapId,
		percentageToBasisPoints(percentage),
		minAmount,
		enviroment,
	);
 
	// ... continue to sign and execute the transaction
	// ...
};

V2 implementation

On the new SDK, the same transaction can be built as follows:

/// You need to do this only once and re-use it in the application.
const kioskClient = new KioskClient({
	client: new SuiClient({
		url: getFullnodeUrl('mainnet'),
	}),
	network: Network.MAINNET,
});
 
const adjustPolicy = async () => {
	const txb = new TransactionBlock();
 
	// You could have more than one cap, since you can create more than one transfer policy.
	const policyCaps = await kioskClient.getOwnedTransferPoliciesByType({
		type: `SomePackageId::type::MyType`,
		address: '0xOwnerAddress',
	});
 
	new TransferPolicyTransaction({ transactionBlock: txb, kioskClient, cap: policyCaps[0] })
		.addRoyaltyRule(percentageToBasisPoints(2.55), 100_000_000)
		.addLockRule();
 
	// ... continue to sign and execute the transaction
	// ...
};