@mysten/kiosk 0.0.0-experimental-20230530145812 → 0.0.0-experimental-20230602192304

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/tx/kiosk.ts CHANGED
@@ -7,19 +7,23 @@ import {
7
7
  TransactionBlock,
8
8
  } from '@mysten/sui.js';
9
9
 
10
- import { ObjectArgument, getTypeWithoutPackageAddress, objArg } from '../utils';
11
- import { KioskListing } from '../query/kiosk';
12
- import { TransferPolicy } from '../bcs';
13
- import { confirmRequest, resolveRoyaltyRule } from './transfer-policy';
14
-
15
- /** The Kiosk module. */
16
- export const KIOSK_MODULE = '0x2::kiosk';
17
-
18
- /** The Kiosk type. */
19
- export const KIOSK_TYPE = `${KIOSK_MODULE}::Kiosk`;
20
-
21
- /** The Kiosk Owner Cap Type */
22
- export const KIOSK_OWNER_CAP = `${KIOSK_MODULE}::KioskOwnerCap`;
10
+ import { getTypeWithoutPackageAddress, objArg } from '../utils';
11
+ import {
12
+ confirmRequest,
13
+ resolveKioskLockRule,
14
+ resolveRoyaltyRule,
15
+ } from './transfer-policy';
16
+ import {
17
+ KIOSK_LOCK_RULE,
18
+ KIOSK_MODULE,
19
+ KIOSK_TYPE,
20
+ ObjectArgument,
21
+ PurchaseAndResolvePoliciesResponse,
22
+ PurchaseOptionalParams,
23
+ ROYALTY_RULE,
24
+ RulesEnvironmentParam,
25
+ TransferPolicy,
26
+ } from '../types';
23
27
 
24
28
  /**
25
29
  * Create a new shared Kiosk and returns the [kiosk, kioskOwnerCap] tuple.
@@ -228,7 +232,12 @@ export function withdrawFromKiosk(
228
232
  ): TransactionArgument {
229
233
  let amountArg =
230
234
  amount !== null
231
- ? tx.pure(amount, 'Option<u64>')
235
+ ? tx.pure(
236
+ {
237
+ Some: amount,
238
+ },
239
+ 'Option<u64>',
240
+ )
232
241
  : tx.pure({ None: true }, 'Option<u64>');
233
242
 
234
243
  let [coin] = tx.moveCall({
@@ -335,46 +344,71 @@ export function returnValue(
335
344
  * Completes the full purchase flow that includes:
336
345
  * 1. Purchasing the item.
337
346
  * 2. Resolving all the transfer policies (if any).
338
- * 3. Returns the PurchasedItem OR places the item in the user's kiosk (if there's a kiosk lock policy).
347
+ * 3. Returns the item and whether the user can transfer it or not.
348
+ *
349
+ * If the item can be transferred, there's an extra transaction required by the user
350
+ * to transfer it to an address or place it in their kiosk.
339
351
  */
340
352
  export function purchaseAndResolvePolicies(
341
353
  tx: TransactionBlock,
342
354
  itemType: string,
343
- listing: KioskListing,
344
- kioskId: string,
345
- itemId: string,
355
+ price: string,
356
+ kiosk: ObjectArgument,
357
+ itemId: SuiAddress,
346
358
  policy: TransferPolicy,
347
- ): TransactionArgument | null {
359
+ environment: RulesEnvironmentParam,
360
+ extraParams?: PurchaseOptionalParams,
361
+ ): PurchaseAndResolvePoliciesResponse {
348
362
  // if we don't pass the listing or the listing doens't have a price, return.
349
- if (!listing || listing?.price === undefined) return null;
363
+ if (price === undefined || typeof price !== 'string')
364
+ throw new Error(`Price of the listing is not supplied.`);
350
365
 
351
366
  // Split the coin for the amount of the listing.
352
- const coin = tx.splitCoins(tx.gas, [tx.pure(listing.price)]);
367
+ const coin = tx.splitCoins(tx.gas, [tx.pure(price, 'u64')]);
353
368
 
354
369
  // initialize the purchase `kiosk::purchase`
355
370
  const [purchasedItem, transferRequest] = purchase(
356
371
  tx,
357
372
  itemType,
358
- kioskId,
373
+ kiosk,
359
374
  itemId,
360
375
  coin,
361
376
  );
362
377
 
363
378
  // Start resolving rules.
364
- // For now, we only support royalty rule.
365
- // Will need some tweaking to make it function properly with the other
366
- // ruleset.
379
+ // Right now we support `kiosk_lock_rule` and `royalty_rule`.
380
+ // They can also be supplied in parallel (supports combination).
381
+ let hasKioskLockRule = false;
382
+
367
383
  for (let rule of policy.rules) {
368
384
  const ruleWithoutAddr = getTypeWithoutPackageAddress(rule);
369
385
 
370
386
  switch (ruleWithoutAddr) {
371
- case 'royalty_rule::Rule':
387
+ case ROYALTY_RULE:
372
388
  resolveRoyaltyRule(
373
389
  tx,
374
390
  itemType,
375
- listing.price,
391
+ price,
392
+ policy.id,
393
+ transferRequest,
394
+ environment,
395
+ );
396
+ break;
397
+ case KIOSK_LOCK_RULE:
398
+ if (!extraParams?.ownedKiosk || !extraParams?.ownedKioskCap)
399
+ throw new Error(
400
+ `This item type ${itemType} has a 'kiosk_lock_rule', but function call is missing user's kiosk and kioskCap params`,
401
+ );
402
+ hasKioskLockRule = true;
403
+ resolveKioskLockRule(
404
+ tx,
405
+ itemType,
406
+ purchasedItem,
407
+ extraParams.ownedKiosk,
408
+ extraParams.ownedKioskCap,
376
409
  policy.id,
377
410
  transferRequest,
411
+ environment,
378
412
  );
379
413
  break;
380
414
  default:
@@ -385,5 +419,8 @@ export function purchaseAndResolvePolicies(
385
419
  // confirm the Transfer Policy request.
386
420
  confirmRequest(tx, itemType, policy.id, transferRequest);
387
421
 
388
- return purchasedItem;
422
+ return {
423
+ item: purchasedItem,
424
+ canTransfer: !hasKioskLockRule,
425
+ };
389
426
  }
@@ -2,15 +2,13 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { TransactionArgument, TransactionBlock } from '@mysten/sui.js';
5
- import { ObjectArgument, objArg } from '../utils';
6
-
7
- /** The Transfer Policy module. */
8
- export const TRANSFER_POLICY_MODULE = '0x2::transfer_policy';
9
-
10
- /** The Transer Policy Rules package address */
11
- // TODO: Figure out how we serve this for both testnet & mainnet (different package)
12
- export const TRANSFER_POLICY_RULES_PACKAGE_ADDRESS =
13
- 'bd8fc1947cf119350184107a3087e2dc27efefa0dd82e25a1f699069fe81a585';
5
+ import { getRulePackageAddress, objArg } from '../utils';
6
+ import { lock } from './kiosk';
7
+ import {
8
+ ObjectArgument,
9
+ RulesEnvironmentParam,
10
+ TRANSFER_POLICY_MODULE,
11
+ } from '../types';
14
12
 
15
13
  /**
16
14
  * Call the `transfer_policy::new` function to create a new transfer policy.
@@ -48,7 +46,7 @@ export function withdrawFromPolicy(
48
46
  ): TransactionArgument {
49
47
  let amountArg =
50
48
  amount !== null
51
- ? tx.pure(amount, 'Option<u64>')
49
+ ? tx.pure({ Some: amount }, 'Option<u64>')
52
50
  : tx.pure({ None: true }, 'Option<u64>');
53
51
 
54
52
  let [profits] = tx.moveCall({
@@ -104,13 +102,14 @@ export function resolveRoyaltyRule(
104
102
  tx: TransactionBlock,
105
103
  itemType: string,
106
104
  price: string,
107
- policyId: string,
105
+ policyId: ObjectArgument,
108
106
  transferRequest: TransactionArgument,
107
+ environment: RulesEnvironmentParam,
109
108
  ) {
110
109
  const policyObj = objArg(tx, policyId);
111
110
  // calculates the amount
112
111
  const [amount] = tx.moveCall({
113
- target: `${TRANSFER_POLICY_RULES_PACKAGE_ADDRESS}::royalty_rule::fee_amount`,
112
+ target: `${getRulePackageAddress(environment)}::royalty_rule::fee_amount`,
114
113
  typeArguments: [itemType],
115
114
  arguments: [policyObj, objArg(tx, price)],
116
115
  });
@@ -120,8 +119,34 @@ export function resolveRoyaltyRule(
120
119
 
121
120
  // pays the policy
122
121
  tx.moveCall({
123
- target: `${TRANSFER_POLICY_RULES_PACKAGE_ADDRESS}::royalty_rule::pay`,
122
+ target: `${getRulePackageAddress(environment)}::royalty_rule::pay`,
124
123
  typeArguments: [itemType],
125
124
  arguments: [policyObj, transferRequest, feeCoin],
126
125
  });
127
126
  }
127
+
128
+ /**
129
+ * Locks the item in the supplied kiosk and
130
+ * proves to the `kiosk_lock` rule that the item was indeed locked,
131
+ * by calling the `kiosk_lock_rule::prove` function to resolve it.
132
+ */
133
+ export function resolveKioskLockRule(
134
+ tx: TransactionBlock,
135
+ itemType: string,
136
+ item: TransactionArgument,
137
+ kiosk: ObjectArgument,
138
+ kioskCap: ObjectArgument,
139
+ policyId: ObjectArgument,
140
+ transferRequest: TransactionArgument,
141
+ environment: RulesEnvironmentParam,
142
+ ) {
143
+ // lock item in the kiosk.
144
+ lock(tx, itemType, kiosk, kioskCap, policyId, item);
145
+
146
+ // proves that the item is locked in the kiosk to the TP.
147
+ tx.moveCall({
148
+ target: `${getRulePackageAddress(environment)}::kiosk_lock_rule::prove`,
149
+ typeArguments: [itemType],
150
+ arguments: [transferRequest, objArg(tx, kiosk)],
151
+ });
152
+ }
@@ -0,0 +1,22 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { SuiAddress } from '@mysten/sui.js';
5
+
6
+ /* A list of environments. */
7
+ export type Environment = 'mainnet' | 'testnet' | 'devnet' | 'custom';
8
+
9
+ /** A Parameter to support enivronments for rules. */
10
+ export type RulesEnvironmentParam = { env: Environment; address?: SuiAddress };
11
+
12
+ /** A default Testnet Environment object */
13
+ export const testnetEnvironment: RulesEnvironmentParam = { env: 'testnet' };
14
+
15
+ /** A default Mainnet Environment object */
16
+ export const mainnetEnvironment: RulesEnvironmentParam = { env: 'mainnet' };
17
+
18
+ /** A helper to easily export a custom environment */
19
+ export const customEnvironment = (address: string): RulesEnvironmentParam => ({
20
+ env: 'custom',
21
+ address,
22
+ });
@@ -0,0 +1,21 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import {
5
+ SharedObjectRef,
6
+ SuiObjectRef,
7
+ TransactionArgument,
8
+ } from '@mysten/sui.js';
9
+
10
+ export * from './kiosk';
11
+ export * from './transfer-policy';
12
+ export * from './env';
13
+
14
+ /**
15
+ * A valid argument for any of the Kiosk functions.
16
+ */
17
+ export type ObjectArgument =
18
+ | string
19
+ | TransactionArgument
20
+ | SharedObjectRef
21
+ | SuiObjectRef;
@@ -0,0 +1,66 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { TransactionArgument } from '@mysten/sui.js';
5
+ import { ObjectArgument } from '.';
6
+
7
+ /** The Kiosk module. */
8
+ export const KIOSK_MODULE = '0x2::kiosk';
9
+
10
+ /** The Kiosk type. */
11
+ export const KIOSK_TYPE = `${KIOSK_MODULE}::Kiosk`;
12
+
13
+ /** The Kiosk Owner Cap Type */
14
+ export const KIOSK_OWNER_CAP = `${KIOSK_MODULE}::KioskOwnerCap`;
15
+
16
+ /** The Kiosk Item Type */
17
+ export const KIOSK_ITEM = `${KIOSK_MODULE}::Item`;
18
+
19
+ /** The Kiosk Listing Type */
20
+ export const KIOSK_LISTING = `${KIOSK_MODULE}::Listing`;
21
+
22
+ /** The Kiosk Lock Type */
23
+ export const KIOSK_LOCK = `${KIOSK_MODULE}::Lock`;
24
+
25
+ /** The Kiosk PurchaseCap type */
26
+ export const KIOSK_PURCHASE_CAP = `${KIOSK_MODULE}::PurchaseCap`;
27
+
28
+ /**
29
+ * The Kiosk object fields (for BCS queries).
30
+ */
31
+ export type Kiosk = {
32
+ id: string;
33
+ profits: string;
34
+ owner: string;
35
+ itemCount: number;
36
+ allowExtensions: boolean;
37
+ };
38
+
39
+ /**
40
+ * PurchaseCap object fields (for BCS queries).
41
+ */
42
+ export type PurchaseCap = {
43
+ id: string;
44
+ kioskId: string;
45
+ itemId: string;
46
+ minPrice: string;
47
+ };
48
+
49
+ /**
50
+ * The response type of a successful purchase flow.
51
+ * Returns the item, and a `canTransfer` param.
52
+ */
53
+ export type PurchaseAndResolvePoliciesResponse = {
54
+ item: TransactionArgument;
55
+ canTransfer: boolean;
56
+ };
57
+
58
+ /**
59
+ * Optional parameters for `purchaseAndResolvePolicies` flow.
60
+ * This gives us the chance to extend the function in further releases
61
+ * without introducing more breaking changes.
62
+ */
63
+ export type PurchaseOptionalParams = {
64
+ ownedKiosk?: ObjectArgument;
65
+ ownedKioskCap?: ObjectArgument;
66
+ };
@@ -0,0 +1,33 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { ObjectOwner } from '@mysten/sui.js';
5
+
6
+ /** The Transfer Policy module. */
7
+ export const TRANSFER_POLICY_MODULE = '0x2::transfer_policy';
8
+
9
+ /** Name of the event emitted when a TransferPolicy for T is created. */
10
+ export const TRANSFER_POLICY_CREATED_EVENT = `${TRANSFER_POLICY_MODULE}::TransferPolicyCreated`;
11
+
12
+ /** The Transfer Policy Type */
13
+ export const TRANSFER_POLICY_TYPE = `${TRANSFER_POLICY_MODULE}::TransferPolicy`;
14
+
15
+ /** The Kiosk Lock Rule */
16
+ export const KIOSK_LOCK_RULE = 'kiosk_lock_rule::Rule';
17
+
18
+ /** The Royalty rule */
19
+ export const ROYALTY_RULE = 'royalty_rule::Rule';
20
+
21
+ /** The `TransferPolicy` object */
22
+ export type TransferPolicy = {
23
+ id: string;
24
+ type: string;
25
+ balance: string;
26
+ rules: string[];
27
+ owner: ObjectOwner;
28
+ };
29
+
30
+ /** Event emitted when a TransferPolicy is created. */
31
+ export type TransferPolicyCreated = {
32
+ id: string;
33
+ };
package/src/utils.ts CHANGED
@@ -13,16 +13,21 @@ import {
13
13
  } from '@mysten/sui.js';
14
14
  import { KioskData, KioskListing } from './query/kiosk';
15
15
  import { DynamicFieldInfo } from '@mysten/sui.js/dist/types/dynamic_fields';
16
- import { bcs, Kiosk } from './bcs';
17
-
18
- /**
19
- * A valid argument for any of the Kiosk functions.
20
- */
21
- export type ObjectArgument =
22
- | string
23
- | TransactionArgument
24
- | SharedObjectRef
25
- | SuiObjectRef;
16
+ import { bcs } from './bcs';
17
+ import { KIOSK_TYPE, Kiosk, RulesEnvironmentParam } from './types';
18
+ import {
19
+ MAINNET_RULES_PACKAGE_ADDRESS,
20
+ TESTNET_RULES_PACKAGE_ADDRESS,
21
+ } from './constants';
22
+
23
+ /* A simple map to the rule package addresses */
24
+ // TODO: Supply the mainnet and devnet addresses.
25
+ export const rulesPackageAddresses = {
26
+ mainnet: MAINNET_RULES_PACKAGE_ADDRESS,
27
+ testnet: TESTNET_RULES_PACKAGE_ADDRESS,
28
+ devnet: '',
29
+ custom: null,
30
+ };
26
31
 
27
32
  /**
28
33
  * Convert any valid input into a TransactionArgument.
@@ -68,7 +73,7 @@ export async function getKioskObject(
68
73
  throw new Error(`Invalid kiosk query: ${id}, expected object, got package`);
69
74
  }
70
75
 
71
- return bcs.de('0x2::kiosk::Kiosk', queryRes.data.bcs!.bcsBytes, 'base64');
76
+ return bcs.de(KIOSK_TYPE, queryRes.data.bcs!.bcsBytes, 'base64');
72
77
  }
73
78
 
74
79
  // helper to extract kiosk data from dynamic fields.
@@ -109,18 +114,18 @@ export function extractKioskData(
109
114
  }
110
115
 
111
116
  // e.g. 0x2::kiosk::Item -> kiosk::Item
112
- export const getTypeWithoutPackageAddress = (type: string) => {
117
+ export function getTypeWithoutPackageAddress(type: string) {
113
118
  return type.split('::').slice(-2).join('::');
114
- };
119
+ }
115
120
 
116
121
  /**
117
122
  * A helper that attaches the listing prices to kiosk listings.
118
123
  */
119
- export const attachListingsAndPrices = (
124
+ export function attachListingsAndPrices(
120
125
  kioskData: KioskData,
121
126
  listings: KioskListing[],
122
127
  listingObjects: SuiObjectResponse[],
123
- ) => {
128
+ ) {
124
129
  // map item listings as {item_id: KioskListing}
125
130
  // for easier mapping on the nex
126
131
  const itemListings = listings.reduce<Record<ObjectId, KioskListing>>(
@@ -143,15 +148,15 @@ export const attachListingsAndPrices = (
143
148
  kioskData.items.map((item) => {
144
149
  item.listing = itemListings[item.objectId] || undefined;
145
150
  });
146
- };
151
+ }
147
152
 
148
153
  /**
149
154
  * A Helper to attach locked state to items in Kiosk Data.
150
155
  */
151
- export const attachLockedItems = (
156
+ export function attachLockedItems(
152
157
  kioskData: KioskData,
153
158
  lockedItemIds: ObjectId[],
154
- ) => {
159
+ ) {
155
160
  // map lock status in an array of type { item_id: true }
156
161
  const lockedStatuses = lockedItemIds.reduce<Record<ObjectId, boolean>>(
157
162
  (acc: Record<ObjectId, boolean>, item: string) => {
@@ -165,4 +170,19 @@ export const attachLockedItems = (
165
170
  kioskData.items.map((item) => {
166
171
  item.isLocked = lockedStatuses[item.objectId] || false;
167
172
  });
168
- };
173
+ }
174
+
175
+ /**
176
+ * A helper to get a rule's environment address.
177
+ */
178
+ export function getRulePackageAddress(
179
+ environment: RulesEnvironmentParam,
180
+ ): string {
181
+ // if we have custom environment, we return it.
182
+ if (environment.env === 'custom') {
183
+ if (!environment.address)
184
+ throw new Error('Please supply the custom package address for rules.');
185
+ return environment.address;
186
+ }
187
+ return rulesPackageAddresses[environment.env];
188
+ }