@1upmonster/duel 0.2.1 → 0.2.3

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.
Files changed (39) hide show
  1. package/README.md +120 -59
  2. package/dist/admin.d.ts +8 -1
  3. package/dist/admin.js +52 -9
  4. package/dist/generated/duel/errors/duel.d.ts +1 -3
  5. package/dist/generated/duel/errors/duel.js +2 -4
  6. package/dist/generated/duel/instructions/index.d.ts +2 -0
  7. package/dist/generated/duel/instructions/index.js +3 -1
  8. package/dist/generated/duel/instructions/joinQueue.d.ts +1 -1
  9. package/dist/generated/duel/instructions/joinQueue.js +3 -3
  10. package/dist/generated/duel/instructions/setupQueuePermission.d.ts +51 -0
  11. package/dist/generated/duel/instructions/setupQueuePermission.js +63 -0
  12. package/dist/generated/duel/instructions/setupTicketPermission.d.ts +54 -0
  13. package/dist/generated/duel/instructions/setupTicketPermission.js +63 -0
  14. package/dist/generated/duel/programs/duel.d.ts +11 -3
  15. package/dist/generated/duel/programs/duel.js +19 -3
  16. package/dist/player.d.ts +8 -1
  17. package/dist/player.js +56 -5
  18. package/dist/tee.d.ts +4 -3
  19. package/dist/tee.js +17 -23
  20. package/dist/transaction.d.ts +2 -0
  21. package/dist/transaction.js +30 -19
  22. package/dist/utils.d.ts +10 -0
  23. package/dist/utils.js +28 -1
  24. package/package.json +1 -1
  25. package/src/admin.ts +67 -7
  26. package/src/duel.json +57 -5
  27. package/src/generated/duel/errors/duel.ts +2 -4
  28. package/src/generated/duel/instructions/index.ts +3 -1
  29. package/src/generated/duel/instructions/joinQueue.ts +3 -3
  30. package/src/generated/duel/instructions/setupQueuePermission.ts +112 -0
  31. package/src/generated/duel/instructions/setupTicketPermission.ts +115 -0
  32. package/src/generated/duel/programs/duel.ts +12 -4
  33. package/src/player.ts +72 -1
  34. package/src/tee.ts +18 -22
  35. package/src/transaction.ts +33 -18
  36. package/src/utils.ts +34 -0
  37. package/src/encryption.ts +0 -154
  38. package/src/idl/private_matchmaking.json +0 -1027
  39. package/src/idl/private_matchmaking.ts +0 -1033
package/src/duel.json CHANGED
@@ -832,6 +832,63 @@
832
832
  }
833
833
  ]
834
834
  },
835
+ {
836
+ "name": "setup_queue_permission",
837
+ "docs": [
838
+ "Set up permission for queue PDA so only the authority can read it on TEE.",
839
+ "Must be called BEFORE delegate_queue while the program still owns the PDA."
840
+ ],
841
+ "discriminator": [
842
+ 223,
843
+ 132,
844
+ 77,
845
+ 15,
846
+ 224,
847
+ 155,
848
+ 125,
849
+ 224
850
+ ],
851
+ "accounts": [
852
+ {
853
+ "name": "queue",
854
+ "pda": {
855
+ "seeds": [
856
+ {
857
+ "kind": "const",
858
+ "value": [
859
+ 113,
860
+ 117,
861
+ 101,
862
+ 117,
863
+ 101
864
+ ]
865
+ },
866
+ {
867
+ "kind": "account",
868
+ "path": "authority"
869
+ }
870
+ ]
871
+ }
872
+ },
873
+ {
874
+ "name": "authority",
875
+ "writable": true,
876
+ "signer": true
877
+ },
878
+ {
879
+ "name": "permission",
880
+ "writable": true
881
+ },
882
+ {
883
+ "name": "permission_program"
884
+ },
885
+ {
886
+ "name": "system_program",
887
+ "address": "11111111111111111111111111111111"
888
+ }
889
+ ],
890
+ "args": []
891
+ },
835
892
  {
836
893
  "name": "setup_ticket_permission",
837
894
  "docs": [
@@ -984,11 +1041,6 @@
984
1041
  "code": 6005,
985
1042
  "name": "InvalidTicketAccount",
986
1043
  "msg": "Invalid ticket account"
987
- },
988
- {
989
- "code": 6006,
990
- "name": "MissingCallbackProgram",
991
- "msg": "Missing or invalid callback program in remaining accounts"
992
1044
  }
993
1045
  ],
994
1046
  "types": [
@@ -21,14 +21,12 @@ export const DUEL_ERROR__INVALID_ELO_SIZE = 0x1773; // 6003
21
21
  export const DUEL_ERROR__INVALID_TICKET_STATUS = 0x1774; // 6004
22
22
  /** InvalidTicketAccount: Invalid ticket account */
23
23
  export const DUEL_ERROR__INVALID_TICKET_ACCOUNT = 0x1775; // 6005
24
- /** MissingCallbackProgram: Missing or invalid callback program in remaining accounts */
25
- export const DUEL_ERROR__MISSING_CALLBACK_PROGRAM = 0x1776; // 6006
26
24
 
27
- export type DuelError = typeof DUEL_ERROR__DATA_TOO_SMALL | typeof DUEL_ERROR__INVALID_ELO_SIZE | typeof DUEL_ERROR__INVALID_TENANT | typeof DUEL_ERROR__INVALID_TICKET_ACCOUNT | typeof DUEL_ERROR__INVALID_TICKET_STATUS | typeof DUEL_ERROR__MISSING_CALLBACK_PROGRAM | typeof DUEL_ERROR__UNAUTHORIZED;
25
+ export type DuelError = typeof DUEL_ERROR__DATA_TOO_SMALL | typeof DUEL_ERROR__INVALID_ELO_SIZE | typeof DUEL_ERROR__INVALID_TENANT | typeof DUEL_ERROR__INVALID_TICKET_ACCOUNT | typeof DUEL_ERROR__INVALID_TICKET_STATUS | typeof DUEL_ERROR__UNAUTHORIZED;
28
26
 
29
27
  let duelErrorMessages: Record<DuelError, string> | undefined;
30
28
  if (process.env.NODE_ENV !== 'production') {
31
- duelErrorMessages = { [DUEL_ERROR__DATA_TOO_SMALL]: `Account data too small for ELO read`, [DUEL_ERROR__INVALID_ELO_SIZE]: `Invalid ELO size (must be 1, 2, 4, or 8 bytes)`, [DUEL_ERROR__INVALID_TENANT]: `Account does not belong to the specified Tenant Program`, [DUEL_ERROR__INVALID_TICKET_ACCOUNT]: `Invalid ticket account`, [DUEL_ERROR__INVALID_TICKET_STATUS]: `Invalid ticket status for this operation`, [DUEL_ERROR__MISSING_CALLBACK_PROGRAM]: `Missing or invalid callback program in remaining accounts`, [DUEL_ERROR__UNAUTHORIZED]: `Unauthorized access` };
29
+ duelErrorMessages = { [DUEL_ERROR__DATA_TOO_SMALL]: `Account data too small for ELO read`, [DUEL_ERROR__INVALID_ELO_SIZE]: `Invalid ELO size (must be 1, 2, 4, or 8 bytes)`, [DUEL_ERROR__INVALID_TENANT]: `Account does not belong to the specified Tenant Program`, [DUEL_ERROR__INVALID_TICKET_ACCOUNT]: `Invalid ticket account`, [DUEL_ERROR__INVALID_TICKET_STATUS]: `Invalid ticket status for this operation`, [DUEL_ERROR__UNAUTHORIZED]: `Unauthorized access` };
32
30
  }
33
31
 
34
32
  export function getDuelErrorMessage(code: DuelError): string {
@@ -16,4 +16,6 @@ export * from './flushMatches';
16
16
  export * from './initializeQueue';
17
17
  export * from './initializeTenant';
18
18
  export * from './joinQueue';
19
- export * from './processUndelegation';
19
+ export * from './processUndelegation';
20
+ export * from './setupQueuePermission';
21
+ export * from './setupTicketPermission';
@@ -15,7 +15,7 @@ export const JOIN_QUEUE_DISCRIMINATOR = new Uint8Array([157, 115, 48, 109, 65, 8
15
15
  export function getJoinQueueDiscriminatorBytes() { return fixEncoderSize(getBytesEncoder(), 8).encode(JOIN_QUEUE_DISCRIMINATOR); }
16
16
 
17
17
  export type JoinQueueInstruction<TProgram extends string = typeof DUEL_PROGRAM_ADDRESS, TAccountQueue extends string | AccountMeta<string> = string, TAccountTenant extends string | AccountMeta<string> = string, TAccountPlayerData extends string | AccountMeta<string> = string, TAccountPlayerTicket extends string | AccountMeta<string> = string, TAccountSigner extends string | AccountMeta<string> = string, TRemainingAccounts extends readonly AccountMeta<string>[] = []> =
18
- Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array> & InstructionWithAccounts<[TAccountQueue extends string ? WritableAccount<TAccountQueue> : TAccountQueue, TAccountTenant extends string ? ReadonlyAccount<TAccountTenant> : TAccountTenant, TAccountPlayerData extends string ? WritableAccount<TAccountPlayerData> : TAccountPlayerData, TAccountPlayerTicket extends string ? WritableAccount<TAccountPlayerTicket> : TAccountPlayerTicket, TAccountSigner extends string ? ReadonlySignerAccount<TAccountSigner> & AccountSignerMeta<TAccountSigner> : TAccountSigner, ...TRemainingAccounts]>;
18
+ Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array> & InstructionWithAccounts<[TAccountQueue extends string ? WritableAccount<TAccountQueue> : TAccountQueue, TAccountTenant extends string ? ReadonlyAccount<TAccountTenant> : TAccountTenant, TAccountPlayerData extends string ? ReadonlyAccount<TAccountPlayerData> : TAccountPlayerData, TAccountPlayerTicket extends string ? WritableAccount<TAccountPlayerTicket> : TAccountPlayerTicket, TAccountSigner extends string ? ReadonlySignerAccount<TAccountSigner> & AccountSignerMeta<TAccountSigner> : TAccountSigner, ...TRemainingAccounts]>;
19
19
 
20
20
  export type JoinQueueInstructionData = { discriminator: ReadonlyUint8Array; };
21
21
 
@@ -46,7 +46,7 @@ export async function getJoinQueueInstructionAsync<TAccountQueue extends string,
46
46
  const programAddress = config?.programAddress ?? DUEL_PROGRAM_ADDRESS;
47
47
 
48
48
  // Original accounts.
49
- const originalAccounts = { queue: { value: input.queue ?? null, isWritable: true }, tenant: { value: input.tenant ?? null, isWritable: false }, playerData: { value: input.playerData ?? null, isWritable: true }, playerTicket: { value: input.playerTicket ?? null, isWritable: true }, signer: { value: input.signer ?? null, isWritable: false } }
49
+ const originalAccounts = { queue: { value: input.queue ?? null, isWritable: true }, tenant: { value: input.tenant ?? null, isWritable: false }, playerData: { value: input.playerData ?? null, isWritable: false }, playerTicket: { value: input.playerTicket ?? null, isWritable: true }, signer: { value: input.signer ?? null, isWritable: false } }
50
50
  const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
51
51
 
52
52
 
@@ -72,7 +72,7 @@ export function getJoinQueueInstruction<TAccountQueue extends string, TAccountTe
72
72
  const programAddress = config?.programAddress ?? DUEL_PROGRAM_ADDRESS;
73
73
 
74
74
  // Original accounts.
75
- const originalAccounts = { queue: { value: input.queue ?? null, isWritable: true }, tenant: { value: input.tenant ?? null, isWritable: false }, playerData: { value: input.playerData ?? null, isWritable: true }, playerTicket: { value: input.playerTicket ?? null, isWritable: true }, signer: { value: input.signer ?? null, isWritable: false } }
75
+ const originalAccounts = { queue: { value: input.queue ?? null, isWritable: true }, tenant: { value: input.tenant ?? null, isWritable: false }, playerData: { value: input.playerData ?? null, isWritable: false }, playerTicket: { value: input.playerTicket ?? null, isWritable: true }, signer: { value: input.signer ?? null, isWritable: false } }
76
76
  const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
77
77
 
78
78
 
@@ -0,0 +1,112 @@
1
+ /**
2
+ * This code was AUTOGENERATED using the Codama library.
3
+ * Please DO NOT EDIT THIS FILE, instead use visitors
4
+ * to add features, then rerun Codama to update it.
5
+ *
6
+ * @see https://github.com/codama-idl/codama
7
+ */
8
+
9
+ import { combineCodec, fixDecoderSize, fixEncoderSize, getAddressEncoder, getBytesDecoder, getBytesEncoder, getProgramDerivedAddress, getStructDecoder, getStructEncoder, SOLANA_ERROR__PROGRAM_CLIENTS__INSUFFICIENT_ACCOUNT_METAS, SolanaError, transformEncoder, type AccountMeta, type AccountSignerMeta, type Address, type FixedSizeCodec, type FixedSizeDecoder, type FixedSizeEncoder, type Instruction, type InstructionWithAccounts, type InstructionWithData, type ReadonlyAccount, type ReadonlyUint8Array, type TransactionSigner, type WritableAccount, type WritableSignerAccount } from '@solana/kit';
10
+ import { getAccountMetaFactory, getAddressFromResolvedInstructionAccount, type ResolvedInstructionAccount } from '@solana/program-client-core';
11
+ import { DUEL_PROGRAM_ADDRESS } from '../programs';
12
+
13
+ export const SETUP_QUEUE_PERMISSION_DISCRIMINATOR = new Uint8Array([223, 132, 77, 15, 224, 155, 125, 224]);
14
+
15
+ export function getSetupQueuePermissionDiscriminatorBytes() { return fixEncoderSize(getBytesEncoder(), 8).encode(SETUP_QUEUE_PERMISSION_DISCRIMINATOR); }
16
+
17
+ export type SetupQueuePermissionInstruction<TProgram extends string = typeof DUEL_PROGRAM_ADDRESS, TAccountQueue extends string | AccountMeta<string> = string, TAccountAuthority extends string | AccountMeta<string> = string, TAccountPermission extends string | AccountMeta<string> = string, TAccountPermissionProgram extends string | AccountMeta<string> = string, TAccountSystemProgram extends string | AccountMeta<string> = "11111111111111111111111111111111", TRemainingAccounts extends readonly AccountMeta<string>[] = []> =
18
+ Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array> & InstructionWithAccounts<[TAccountQueue extends string ? ReadonlyAccount<TAccountQueue> : TAccountQueue, TAccountAuthority extends string ? WritableSignerAccount<TAccountAuthority> & AccountSignerMeta<TAccountAuthority> : TAccountAuthority, TAccountPermission extends string ? WritableAccount<TAccountPermission> : TAccountPermission, TAccountPermissionProgram extends string ? ReadonlyAccount<TAccountPermissionProgram> : TAccountPermissionProgram, TAccountSystemProgram extends string ? ReadonlyAccount<TAccountSystemProgram> : TAccountSystemProgram, ...TRemainingAccounts]>;
19
+
20
+ export type SetupQueuePermissionInstructionData = { discriminator: ReadonlyUint8Array; };
21
+
22
+ export type SetupQueuePermissionInstructionDataArgs = { };
23
+
24
+ export function getSetupQueuePermissionInstructionDataEncoder(): FixedSizeEncoder<SetupQueuePermissionInstructionDataArgs> {
25
+ return transformEncoder(getStructEncoder([['discriminator', fixEncoderSize(getBytesEncoder(), 8)]]), (value) => ({ ...value, discriminator: SETUP_QUEUE_PERMISSION_DISCRIMINATOR }));
26
+ }
27
+
28
+ export function getSetupQueuePermissionInstructionDataDecoder(): FixedSizeDecoder<SetupQueuePermissionInstructionData> {
29
+ return getStructDecoder([['discriminator', fixDecoderSize(getBytesDecoder(), 8)]]);
30
+ }
31
+
32
+ export function getSetupQueuePermissionInstructionDataCodec(): FixedSizeCodec<SetupQueuePermissionInstructionDataArgs, SetupQueuePermissionInstructionData> {
33
+ return combineCodec(getSetupQueuePermissionInstructionDataEncoder(), getSetupQueuePermissionInstructionDataDecoder());
34
+ }
35
+
36
+ export type SetupQueuePermissionAsyncInput<TAccountQueue extends string = string, TAccountAuthority extends string = string, TAccountPermission extends string = string, TAccountPermissionProgram extends string = string, TAccountSystemProgram extends string = string> = {
37
+ queue?: Address<TAccountQueue>;
38
+ authority: TransactionSigner<TAccountAuthority>;
39
+ permission: Address<TAccountPermission>;
40
+ permissionProgram: Address<TAccountPermissionProgram>;
41
+ systemProgram?: Address<TAccountSystemProgram>;
42
+ }
43
+
44
+ export async function getSetupQueuePermissionInstructionAsync<TAccountQueue extends string, TAccountAuthority extends string, TAccountPermission extends string, TAccountPermissionProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof DUEL_PROGRAM_ADDRESS>(input: SetupQueuePermissionAsyncInput<TAccountQueue, TAccountAuthority, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>, config?: { programAddress?: TProgramAddress } ): Promise<SetupQueuePermissionInstruction<TProgramAddress, TAccountQueue, TAccountAuthority, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>> {
45
+ // Program address.
46
+ const programAddress = config?.programAddress ?? DUEL_PROGRAM_ADDRESS;
47
+
48
+ // Original accounts.
49
+ const originalAccounts = { queue: { value: input.queue ?? null, isWritable: false }, authority: { value: input.authority ?? null, isWritable: true }, permission: { value: input.permission ?? null, isWritable: true }, permissionProgram: { value: input.permissionProgram ?? null, isWritable: false }, systemProgram: { value: input.systemProgram ?? null, isWritable: false } }
50
+ const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
51
+
52
+
53
+ // Resolve default values.
54
+ if (!accounts.queue.value) {
55
+ accounts.queue.value = await getProgramDerivedAddress({ programAddress, seeds: [getBytesEncoder().encode(new Uint8Array([113, 117, 101, 117, 101])), getAddressEncoder().encode(getAddressFromResolvedInstructionAccount("authority", accounts.authority.value))] });
56
+ }
57
+ if (!accounts.systemProgram.value) {
58
+ accounts.systemProgram.value = '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>;
59
+ }
60
+
61
+ const getAccountMeta = getAccountMetaFactory(programAddress, 'programId');
62
+ return Object.freeze({ accounts: [getAccountMeta("queue", accounts.queue), getAccountMeta("authority", accounts.authority), getAccountMeta("permission", accounts.permission), getAccountMeta("permissionProgram", accounts.permissionProgram), getAccountMeta("systemProgram", accounts.systemProgram)], data: getSetupQueuePermissionInstructionDataEncoder().encode({}), programAddress } as SetupQueuePermissionInstruction<TProgramAddress, TAccountQueue, TAccountAuthority, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>);
63
+ }
64
+
65
+ export type SetupQueuePermissionInput<TAccountQueue extends string = string, TAccountAuthority extends string = string, TAccountPermission extends string = string, TAccountPermissionProgram extends string = string, TAccountSystemProgram extends string = string> = {
66
+ queue: Address<TAccountQueue>;
67
+ authority: TransactionSigner<TAccountAuthority>;
68
+ permission: Address<TAccountPermission>;
69
+ permissionProgram: Address<TAccountPermissionProgram>;
70
+ systemProgram?: Address<TAccountSystemProgram>;
71
+ }
72
+
73
+ export function getSetupQueuePermissionInstruction<TAccountQueue extends string, TAccountAuthority extends string, TAccountPermission extends string, TAccountPermissionProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof DUEL_PROGRAM_ADDRESS>(input: SetupQueuePermissionInput<TAccountQueue, TAccountAuthority, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>, config?: { programAddress?: TProgramAddress } ): SetupQueuePermissionInstruction<TProgramAddress, TAccountQueue, TAccountAuthority, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram> {
74
+ // Program address.
75
+ const programAddress = config?.programAddress ?? DUEL_PROGRAM_ADDRESS;
76
+
77
+ // Original accounts.
78
+ const originalAccounts = { queue: { value: input.queue ?? null, isWritable: false }, authority: { value: input.authority ?? null, isWritable: true }, permission: { value: input.permission ?? null, isWritable: true }, permissionProgram: { value: input.permissionProgram ?? null, isWritable: false }, systemProgram: { value: input.systemProgram ?? null, isWritable: false } }
79
+ const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
80
+
81
+
82
+ // Resolve default values.
83
+ if (!accounts.systemProgram.value) {
84
+ accounts.systemProgram.value = '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>;
85
+ }
86
+
87
+ const getAccountMeta = getAccountMetaFactory(programAddress, 'programId');
88
+ return Object.freeze({ accounts: [getAccountMeta("queue", accounts.queue), getAccountMeta("authority", accounts.authority), getAccountMeta("permission", accounts.permission), getAccountMeta("permissionProgram", accounts.permissionProgram), getAccountMeta("systemProgram", accounts.systemProgram)], data: getSetupQueuePermissionInstructionDataEncoder().encode({}), programAddress } as SetupQueuePermissionInstruction<TProgramAddress, TAccountQueue, TAccountAuthority, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>);
89
+ }
90
+
91
+ export type ParsedSetupQueuePermissionInstruction<TProgram extends string = typeof DUEL_PROGRAM_ADDRESS, TAccountMetas extends readonly AccountMeta[] = readonly AccountMeta[]> = { programAddress: Address<TProgram>;
92
+ accounts: {
93
+ queue: TAccountMetas[0];
94
+ authority: TAccountMetas[1];
95
+ permission: TAccountMetas[2];
96
+ permissionProgram: TAccountMetas[3];
97
+ systemProgram: TAccountMetas[4];
98
+ };
99
+ data: SetupQueuePermissionInstructionData; };
100
+
101
+ export function parseSetupQueuePermissionInstruction<TProgram extends string, TAccountMetas extends readonly AccountMeta[]>(instruction: Instruction<TProgram> & InstructionWithAccounts<TAccountMetas> & InstructionWithData<ReadonlyUint8Array>): ParsedSetupQueuePermissionInstruction<TProgram, TAccountMetas> {
102
+ if (instruction.accounts.length < 5) {
103
+ throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__INSUFFICIENT_ACCOUNT_METAS, { actualAccountMetas: instruction.accounts.length, expectedAccountMetas: 5 });
104
+ }
105
+ let accountIndex = 0;
106
+ const getNextAccount = () => {
107
+ const accountMeta = (instruction.accounts as TAccountMetas)[accountIndex]!;
108
+ accountIndex += 1;
109
+ return accountMeta;
110
+ }
111
+ return { programAddress: instruction.programAddress, accounts: { queue: getNextAccount(), authority: getNextAccount(), permission: getNextAccount(), permissionProgram: getNextAccount(), systemProgram: getNextAccount() }, data: getSetupQueuePermissionInstructionDataDecoder().decode(instruction.data) };
112
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * This code was AUTOGENERATED using the Codama library.
3
+ * Please DO NOT EDIT THIS FILE, instead use visitors
4
+ * to add features, then rerun Codama to update it.
5
+ *
6
+ * @see https://github.com/codama-idl/codama
7
+ */
8
+
9
+ import { combineCodec, fixDecoderSize, fixEncoderSize, getAddressEncoder, getBytesDecoder, getBytesEncoder, getProgramDerivedAddress, getStructDecoder, getStructEncoder, SOLANA_ERROR__PROGRAM_CLIENTS__INSUFFICIENT_ACCOUNT_METAS, SolanaError, transformEncoder, type AccountMeta, type AccountSignerMeta, type Address, type FixedSizeCodec, type FixedSizeDecoder, type FixedSizeEncoder, type Instruction, type InstructionWithAccounts, type InstructionWithData, type ReadonlyAccount, type ReadonlyUint8Array, type TransactionSigner, type WritableAccount, type WritableSignerAccount } from '@solana/kit';
10
+ import { getAccountMetaFactory, getAddressFromResolvedInstructionAccount, type ResolvedInstructionAccount } from '@solana/program-client-core';
11
+ import { DUEL_PROGRAM_ADDRESS } from '../programs';
12
+
13
+ export const SETUP_TICKET_PERMISSION_DISCRIMINATOR = new Uint8Array([164, 29, 7, 235, 183, 223, 11, 85]);
14
+
15
+ export function getSetupTicketPermissionDiscriminatorBytes() { return fixEncoderSize(getBytesEncoder(), 8).encode(SETUP_TICKET_PERMISSION_DISCRIMINATOR); }
16
+
17
+ export type SetupTicketPermissionInstruction<TProgram extends string = typeof DUEL_PROGRAM_ADDRESS, TAccountTicket extends string | AccountMeta<string> = string, TAccountTenant extends string | AccountMeta<string> = string, TAccountPlayer extends string | AccountMeta<string> = string, TAccountPermission extends string | AccountMeta<string> = string, TAccountPermissionProgram extends string | AccountMeta<string> = string, TAccountSystemProgram extends string | AccountMeta<string> = "11111111111111111111111111111111", TRemainingAccounts extends readonly AccountMeta<string>[] = []> =
18
+ Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array> & InstructionWithAccounts<[TAccountTicket extends string ? ReadonlyAccount<TAccountTicket> : TAccountTicket, TAccountTenant extends string ? ReadonlyAccount<TAccountTenant> : TAccountTenant, TAccountPlayer extends string ? WritableSignerAccount<TAccountPlayer> & AccountSignerMeta<TAccountPlayer> : TAccountPlayer, TAccountPermission extends string ? WritableAccount<TAccountPermission> : TAccountPermission, TAccountPermissionProgram extends string ? ReadonlyAccount<TAccountPermissionProgram> : TAccountPermissionProgram, TAccountSystemProgram extends string ? ReadonlyAccount<TAccountSystemProgram> : TAccountSystemProgram, ...TRemainingAccounts]>;
19
+
20
+ export type SetupTicketPermissionInstructionData = { discriminator: ReadonlyUint8Array; };
21
+
22
+ export type SetupTicketPermissionInstructionDataArgs = { };
23
+
24
+ export function getSetupTicketPermissionInstructionDataEncoder(): FixedSizeEncoder<SetupTicketPermissionInstructionDataArgs> {
25
+ return transformEncoder(getStructEncoder([['discriminator', fixEncoderSize(getBytesEncoder(), 8)]]), (value) => ({ ...value, discriminator: SETUP_TICKET_PERMISSION_DISCRIMINATOR }));
26
+ }
27
+
28
+ export function getSetupTicketPermissionInstructionDataDecoder(): FixedSizeDecoder<SetupTicketPermissionInstructionData> {
29
+ return getStructDecoder([['discriminator', fixDecoderSize(getBytesDecoder(), 8)]]);
30
+ }
31
+
32
+ export function getSetupTicketPermissionInstructionDataCodec(): FixedSizeCodec<SetupTicketPermissionInstructionDataArgs, SetupTicketPermissionInstructionData> {
33
+ return combineCodec(getSetupTicketPermissionInstructionDataEncoder(), getSetupTicketPermissionInstructionDataDecoder());
34
+ }
35
+
36
+ export type SetupTicketPermissionAsyncInput<TAccountTicket extends string = string, TAccountTenant extends string = string, TAccountPlayer extends string = string, TAccountPermission extends string = string, TAccountPermissionProgram extends string = string, TAccountSystemProgram extends string = string> = {
37
+ ticket?: Address<TAccountTicket>;
38
+ tenant: Address<TAccountTenant>;
39
+ player: TransactionSigner<TAccountPlayer>;
40
+ permission: Address<TAccountPermission>;
41
+ permissionProgram: Address<TAccountPermissionProgram>;
42
+ systemProgram?: Address<TAccountSystemProgram>;
43
+ }
44
+
45
+ export async function getSetupTicketPermissionInstructionAsync<TAccountTicket extends string, TAccountTenant extends string, TAccountPlayer extends string, TAccountPermission extends string, TAccountPermissionProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof DUEL_PROGRAM_ADDRESS>(input: SetupTicketPermissionAsyncInput<TAccountTicket, TAccountTenant, TAccountPlayer, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>, config?: { programAddress?: TProgramAddress } ): Promise<SetupTicketPermissionInstruction<TProgramAddress, TAccountTicket, TAccountTenant, TAccountPlayer, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>> {
46
+ // Program address.
47
+ const programAddress = config?.programAddress ?? DUEL_PROGRAM_ADDRESS;
48
+
49
+ // Original accounts.
50
+ const originalAccounts = { ticket: { value: input.ticket ?? null, isWritable: false }, tenant: { value: input.tenant ?? null, isWritable: false }, player: { value: input.player ?? null, isWritable: true }, permission: { value: input.permission ?? null, isWritable: true }, permissionProgram: { value: input.permissionProgram ?? null, isWritable: false }, systemProgram: { value: input.systemProgram ?? null, isWritable: false } }
51
+ const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
52
+
53
+
54
+ // Resolve default values.
55
+ if (!accounts.ticket.value) {
56
+ accounts.ticket.value = await getProgramDerivedAddress({ programAddress, seeds: [getBytesEncoder().encode(new Uint8Array([116, 105, 99, 107, 101, 116])), getAddressEncoder().encode(getAddressFromResolvedInstructionAccount("player", accounts.player.value)), getAddressEncoder().encode(getAddressFromResolvedInstructionAccount("tenant", accounts.tenant.value))] });
57
+ }
58
+ if (!accounts.systemProgram.value) {
59
+ accounts.systemProgram.value = '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>;
60
+ }
61
+
62
+ const getAccountMeta = getAccountMetaFactory(programAddress, 'programId');
63
+ return Object.freeze({ accounts: [getAccountMeta("ticket", accounts.ticket), getAccountMeta("tenant", accounts.tenant), getAccountMeta("player", accounts.player), getAccountMeta("permission", accounts.permission), getAccountMeta("permissionProgram", accounts.permissionProgram), getAccountMeta("systemProgram", accounts.systemProgram)], data: getSetupTicketPermissionInstructionDataEncoder().encode({}), programAddress } as SetupTicketPermissionInstruction<TProgramAddress, TAccountTicket, TAccountTenant, TAccountPlayer, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>);
64
+ }
65
+
66
+ export type SetupTicketPermissionInput<TAccountTicket extends string = string, TAccountTenant extends string = string, TAccountPlayer extends string = string, TAccountPermission extends string = string, TAccountPermissionProgram extends string = string, TAccountSystemProgram extends string = string> = {
67
+ ticket: Address<TAccountTicket>;
68
+ tenant: Address<TAccountTenant>;
69
+ player: TransactionSigner<TAccountPlayer>;
70
+ permission: Address<TAccountPermission>;
71
+ permissionProgram: Address<TAccountPermissionProgram>;
72
+ systemProgram?: Address<TAccountSystemProgram>;
73
+ }
74
+
75
+ export function getSetupTicketPermissionInstruction<TAccountTicket extends string, TAccountTenant extends string, TAccountPlayer extends string, TAccountPermission extends string, TAccountPermissionProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof DUEL_PROGRAM_ADDRESS>(input: SetupTicketPermissionInput<TAccountTicket, TAccountTenant, TAccountPlayer, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>, config?: { programAddress?: TProgramAddress } ): SetupTicketPermissionInstruction<TProgramAddress, TAccountTicket, TAccountTenant, TAccountPlayer, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram> {
76
+ // Program address.
77
+ const programAddress = config?.programAddress ?? DUEL_PROGRAM_ADDRESS;
78
+
79
+ // Original accounts.
80
+ const originalAccounts = { ticket: { value: input.ticket ?? null, isWritable: false }, tenant: { value: input.tenant ?? null, isWritable: false }, player: { value: input.player ?? null, isWritable: true }, permission: { value: input.permission ?? null, isWritable: true }, permissionProgram: { value: input.permissionProgram ?? null, isWritable: false }, systemProgram: { value: input.systemProgram ?? null, isWritable: false } }
81
+ const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
82
+
83
+
84
+ // Resolve default values.
85
+ if (!accounts.systemProgram.value) {
86
+ accounts.systemProgram.value = '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>;
87
+ }
88
+
89
+ const getAccountMeta = getAccountMetaFactory(programAddress, 'programId');
90
+ return Object.freeze({ accounts: [getAccountMeta("ticket", accounts.ticket), getAccountMeta("tenant", accounts.tenant), getAccountMeta("player", accounts.player), getAccountMeta("permission", accounts.permission), getAccountMeta("permissionProgram", accounts.permissionProgram), getAccountMeta("systemProgram", accounts.systemProgram)], data: getSetupTicketPermissionInstructionDataEncoder().encode({}), programAddress } as SetupTicketPermissionInstruction<TProgramAddress, TAccountTicket, TAccountTenant, TAccountPlayer, TAccountPermission, TAccountPermissionProgram, TAccountSystemProgram>);
91
+ }
92
+
93
+ export type ParsedSetupTicketPermissionInstruction<TProgram extends string = typeof DUEL_PROGRAM_ADDRESS, TAccountMetas extends readonly AccountMeta[] = readonly AccountMeta[]> = { programAddress: Address<TProgram>;
94
+ accounts: {
95
+ ticket: TAccountMetas[0];
96
+ tenant: TAccountMetas[1];
97
+ player: TAccountMetas[2];
98
+ permission: TAccountMetas[3];
99
+ permissionProgram: TAccountMetas[4];
100
+ systemProgram: TAccountMetas[5];
101
+ };
102
+ data: SetupTicketPermissionInstructionData; };
103
+
104
+ export function parseSetupTicketPermissionInstruction<TProgram extends string, TAccountMetas extends readonly AccountMeta[]>(instruction: Instruction<TProgram> & InstructionWithAccounts<TAccountMetas> & InstructionWithData<ReadonlyUint8Array>): ParsedSetupTicketPermissionInstruction<TProgram, TAccountMetas> {
105
+ if (instruction.accounts.length < 6) {
106
+ throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__INSUFFICIENT_ACCOUNT_METAS, { actualAccountMetas: instruction.accounts.length, expectedAccountMetas: 6 });
107
+ }
108
+ let accountIndex = 0;
109
+ const getNextAccount = () => {
110
+ const accountMeta = (instruction.accounts as TAccountMetas)[accountIndex]!;
111
+ accountIndex += 1;
112
+ return accountMeta;
113
+ }
114
+ return { programAddress: instruction.programAddress, accounts: { ticket: getNextAccount(), tenant: getNextAccount(), player: getNextAccount(), permission: getNextAccount(), permissionProgram: getNextAccount(), systemProgram: getNextAccount() }, data: getSetupTicketPermissionInstructionDataDecoder().decode(instruction.data) };
115
+ }
@@ -9,7 +9,7 @@
9
9
  import { assertIsInstructionWithAccounts, containsBytes, fixEncoderSize, getBytesEncoder, SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_ACCOUNT, SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_INSTRUCTION, SOLANA_ERROR__PROGRAM_CLIENTS__UNRECOGNIZED_INSTRUCTION_TYPE, SolanaError, type Address, type ClientWithPayer, type ClientWithRpc, type ClientWithTransactionPlanning, type ClientWithTransactionSending, type GetAccountInfoApi, type GetMultipleAccountsApi, type Instruction, type InstructionWithData, type ReadonlyUint8Array } from '@solana/kit';
10
10
  import { addSelfFetchFunctions, addSelfPlanAndSendFunctions, type SelfFetchFunctions, type SelfPlanAndSendFunctions } from '@solana/program-client-core';
11
11
  import { getMatchTicketCodec, getQueueCodec, getTenantCodec, type MatchTicket, type MatchTicketArgs, type Queue, type QueueArgs, type Tenant, type TenantArgs } from '../accounts';
12
- import { getCancelTicketInstructionAsync, getCloseTicketInstructionAsync, getCommitTicketsInstruction, getCreateTicketInstructionAsync, getDelegateQueueInstructionAsync, getDelegateTicketInstructionAsync, getFlushMatchesInstruction, getInitializeQueueInstructionAsync, getInitializeTenantInstructionAsync, getJoinQueueInstructionAsync, getProcessUndelegationInstruction, parseCancelTicketInstruction, parseCloseTicketInstruction, parseCommitTicketsInstruction, parseCreateTicketInstruction, parseDelegateQueueInstruction, parseDelegateTicketInstruction, parseFlushMatchesInstruction, parseInitializeQueueInstruction, parseInitializeTenantInstruction, parseJoinQueueInstruction, parseProcessUndelegationInstruction, type CancelTicketAsyncInput, type CloseTicketAsyncInput, type CommitTicketsInput, type CreateTicketAsyncInput, type DelegateQueueAsyncInput, type DelegateTicketAsyncInput, type FlushMatchesInput, type InitializeQueueAsyncInput, type InitializeTenantAsyncInput, type JoinQueueAsyncInput, type ParsedCancelTicketInstruction, type ParsedCloseTicketInstruction, type ParsedCommitTicketsInstruction, type ParsedCreateTicketInstruction, type ParsedDelegateQueueInstruction, type ParsedDelegateTicketInstruction, type ParsedFlushMatchesInstruction, type ParsedInitializeQueueInstruction, type ParsedInitializeTenantInstruction, type ParsedJoinQueueInstruction, type ParsedProcessUndelegationInstruction, type ProcessUndelegationInput } from '../instructions';
12
+ import { getCancelTicketInstructionAsync, getCloseTicketInstructionAsync, getCommitTicketsInstruction, getCreateTicketInstructionAsync, getDelegateQueueInstructionAsync, getDelegateTicketInstructionAsync, getFlushMatchesInstruction, getInitializeQueueInstructionAsync, getInitializeTenantInstructionAsync, getJoinQueueInstructionAsync, getProcessUndelegationInstruction, getSetupQueuePermissionInstructionAsync, getSetupTicketPermissionInstructionAsync, parseCancelTicketInstruction, parseCloseTicketInstruction, parseCommitTicketsInstruction, parseCreateTicketInstruction, parseDelegateQueueInstruction, parseDelegateTicketInstruction, parseFlushMatchesInstruction, parseInitializeQueueInstruction, parseInitializeTenantInstruction, parseJoinQueueInstruction, parseProcessUndelegationInstruction, parseSetupQueuePermissionInstruction, parseSetupTicketPermissionInstruction, type CancelTicketAsyncInput, type CloseTicketAsyncInput, type CommitTicketsInput, type CreateTicketAsyncInput, type DelegateQueueAsyncInput, type DelegateTicketAsyncInput, type FlushMatchesInput, type InitializeQueueAsyncInput, type InitializeTenantAsyncInput, type JoinQueueAsyncInput, type ParsedCancelTicketInstruction, type ParsedCloseTicketInstruction, type ParsedCommitTicketsInstruction, type ParsedCreateTicketInstruction, type ParsedDelegateQueueInstruction, type ParsedDelegateTicketInstruction, type ParsedFlushMatchesInstruction, type ParsedInitializeQueueInstruction, type ParsedInitializeTenantInstruction, type ParsedJoinQueueInstruction, type ParsedProcessUndelegationInstruction, type ParsedSetupQueuePermissionInstruction, type ParsedSetupTicketPermissionInstruction, type ProcessUndelegationInput, type SetupQueuePermissionAsyncInput, type SetupTicketPermissionAsyncInput } from '../instructions';
13
13
 
14
14
  export const DUEL_PROGRAM_ADDRESS = 'EdZzUwKd1X2ZWjxLPpz1cpEzMF7RUZC43Pq64v1VcK5X' as Address<'EdZzUwKd1X2ZWjxLPpz1cpEzMF7RUZC43Pq64v1VcK5X'>;
15
15
 
@@ -23,7 +23,7 @@ if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Arr
23
23
  throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_ACCOUNT, { accountData: data, programName: "duel" });
24
24
  }
25
25
 
26
- export enum DuelInstruction { CancelTicket, CloseTicket, CommitTickets, CreateTicket, DelegateQueue, DelegateTicket, FlushMatches, InitializeQueue, InitializeTenant, JoinQueue, ProcessUndelegation }
26
+ export enum DuelInstruction { CancelTicket, CloseTicket, CommitTickets, CreateTicket, DelegateQueue, DelegateTicket, FlushMatches, InitializeQueue, InitializeTenant, JoinQueue, ProcessUndelegation, SetupQueuePermission, SetupTicketPermission }
27
27
 
28
28
  export function identifyDuelInstruction(instruction: { data: ReadonlyUint8Array } | ReadonlyUint8Array): DuelInstruction {
29
29
  const data = 'data' in instruction ? instruction.data : instruction;
@@ -38,6 +38,8 @@ if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Arr
38
38
  if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Array([94, 120, 34, 186, 57, 167, 241, 206])), 0)) { return DuelInstruction.InitializeTenant; }
39
39
  if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Array([157, 115, 48, 109, 65, 86, 203, 238])), 0)) { return DuelInstruction.JoinQueue; }
40
40
  if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Array([196, 28, 41, 206, 48, 37, 51, 167])), 0)) { return DuelInstruction.ProcessUndelegation; }
41
+ if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Array([223, 132, 77, 15, 224, 155, 125, 224])), 0)) { return DuelInstruction.SetupQueuePermission; }
42
+ if (containsBytes(data, fixEncoderSize(getBytesEncoder(), 8).encode(new Uint8Array([164, 29, 7, 235, 183, 223, 11, 85])), 0)) { return DuelInstruction.SetupTicketPermission; }
41
43
  throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_INSTRUCTION, { instructionData: data, programName: "duel" });
42
44
  }
43
45
 
@@ -53,6 +55,8 @@ export type ParsedDuelInstruction<TProgram extends string = 'EdZzUwKd1X2ZWjxLPpz
53
55
  | { instructionType: DuelInstruction.InitializeTenant } & ParsedInitializeTenantInstruction<TProgram>
54
56
  | { instructionType: DuelInstruction.JoinQueue } & ParsedJoinQueueInstruction<TProgram>
55
57
  | { instructionType: DuelInstruction.ProcessUndelegation } & ParsedProcessUndelegationInstruction<TProgram>
58
+ | { instructionType: DuelInstruction.SetupQueuePermission } & ParsedSetupQueuePermissionInstruction<TProgram>
59
+ | { instructionType: DuelInstruction.SetupTicketPermission } & ParsedSetupTicketPermissionInstruction<TProgram>
56
60
 
57
61
 
58
62
  export function parseDuelInstruction<TProgram extends string>(
@@ -83,6 +87,10 @@ case DuelInstruction.JoinQueue: { assertIsInstructionWithAccounts(instruction);
83
87
  return { instructionType: DuelInstruction.JoinQueue, ...parseJoinQueueInstruction(instruction) }; }
84
88
  case DuelInstruction.ProcessUndelegation: { assertIsInstructionWithAccounts(instruction);
85
89
  return { instructionType: DuelInstruction.ProcessUndelegation, ...parseProcessUndelegationInstruction(instruction) }; }
90
+ case DuelInstruction.SetupQueuePermission: { assertIsInstructionWithAccounts(instruction);
91
+ return { instructionType: DuelInstruction.SetupQueuePermission, ...parseSetupQueuePermissionInstruction(instruction) }; }
92
+ case DuelInstruction.SetupTicketPermission: { assertIsInstructionWithAccounts(instruction);
93
+ return { instructionType: DuelInstruction.SetupTicketPermission, ...parseSetupTicketPermissionInstruction(instruction) }; }
86
94
  default: throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNRECOGNIZED_INSTRUCTION_TYPE, { instructionType: instructionType as string, programName: "duel" });
87
95
  }
88
96
  }
@@ -91,13 +99,13 @@ export type DuelPlugin = { accounts: DuelPluginAccounts; instructions: DuelPlugi
91
99
 
92
100
  export type DuelPluginAccounts = { matchTicket: ReturnType<typeof getMatchTicketCodec> & SelfFetchFunctions<MatchTicketArgs, MatchTicket>; queue: ReturnType<typeof getQueueCodec> & SelfFetchFunctions<QueueArgs, Queue>; tenant: ReturnType<typeof getTenantCodec> & SelfFetchFunctions<TenantArgs, Tenant>; }
93
101
 
94
- export type DuelPluginInstructions = { cancelTicket: (input: CancelTicketAsyncInput) => ReturnType<typeof getCancelTicketInstructionAsync> & SelfPlanAndSendFunctions; closeTicket: (input: CloseTicketAsyncInput) => ReturnType<typeof getCloseTicketInstructionAsync> & SelfPlanAndSendFunctions; commitTickets: (input: MakeOptional<CommitTicketsInput, "payer">) => ReturnType<typeof getCommitTicketsInstruction> & SelfPlanAndSendFunctions; createTicket: (input: CreateTicketAsyncInput) => ReturnType<typeof getCreateTicketInstructionAsync> & SelfPlanAndSendFunctions; delegateQueue: (input: MakeOptional<DelegateQueueAsyncInput, "payer">) => ReturnType<typeof getDelegateQueueInstructionAsync> & SelfPlanAndSendFunctions; delegateTicket: (input: MakeOptional<DelegateTicketAsyncInput, "payer">) => ReturnType<typeof getDelegateTicketInstructionAsync> & SelfPlanAndSendFunctions; flushMatches: (input: FlushMatchesInput) => ReturnType<typeof getFlushMatchesInstruction> & SelfPlanAndSendFunctions; initializeQueue: (input: InitializeQueueAsyncInput) => ReturnType<typeof getInitializeQueueInstructionAsync> & SelfPlanAndSendFunctions; initializeTenant: (input: InitializeTenantAsyncInput) => ReturnType<typeof getInitializeTenantInstructionAsync> & SelfPlanAndSendFunctions; joinQueue: (input: JoinQueueAsyncInput) => ReturnType<typeof getJoinQueueInstructionAsync> & SelfPlanAndSendFunctions; processUndelegation: (input: MakeOptional<ProcessUndelegationInput, "payer">) => ReturnType<typeof getProcessUndelegationInstruction> & SelfPlanAndSendFunctions; }
102
+ export type DuelPluginInstructions = { cancelTicket: (input: CancelTicketAsyncInput) => ReturnType<typeof getCancelTicketInstructionAsync> & SelfPlanAndSendFunctions; closeTicket: (input: CloseTicketAsyncInput) => ReturnType<typeof getCloseTicketInstructionAsync> & SelfPlanAndSendFunctions; commitTickets: (input: MakeOptional<CommitTicketsInput, "payer">) => ReturnType<typeof getCommitTicketsInstruction> & SelfPlanAndSendFunctions; createTicket: (input: CreateTicketAsyncInput) => ReturnType<typeof getCreateTicketInstructionAsync> & SelfPlanAndSendFunctions; delegateQueue: (input: MakeOptional<DelegateQueueAsyncInput, "payer">) => ReturnType<typeof getDelegateQueueInstructionAsync> & SelfPlanAndSendFunctions; delegateTicket: (input: MakeOptional<DelegateTicketAsyncInput, "payer">) => ReturnType<typeof getDelegateTicketInstructionAsync> & SelfPlanAndSendFunctions; flushMatches: (input: FlushMatchesInput) => ReturnType<typeof getFlushMatchesInstruction> & SelfPlanAndSendFunctions; initializeQueue: (input: InitializeQueueAsyncInput) => ReturnType<typeof getInitializeQueueInstructionAsync> & SelfPlanAndSendFunctions; initializeTenant: (input: InitializeTenantAsyncInput) => ReturnType<typeof getInitializeTenantInstructionAsync> & SelfPlanAndSendFunctions; joinQueue: (input: JoinQueueAsyncInput) => ReturnType<typeof getJoinQueueInstructionAsync> & SelfPlanAndSendFunctions; processUndelegation: (input: MakeOptional<ProcessUndelegationInput, "payer">) => ReturnType<typeof getProcessUndelegationInstruction> & SelfPlanAndSendFunctions; setupQueuePermission: (input: SetupQueuePermissionAsyncInput) => ReturnType<typeof getSetupQueuePermissionInstructionAsync> & SelfPlanAndSendFunctions; setupTicketPermission: (input: SetupTicketPermissionAsyncInput) => ReturnType<typeof getSetupTicketPermissionInstructionAsync> & SelfPlanAndSendFunctions; }
95
103
 
96
104
  export type DuelPluginRequirements = ClientWithRpc<GetAccountInfoApi & GetMultipleAccountsApi> & ClientWithPayer & ClientWithTransactionPlanning & ClientWithTransactionSending
97
105
 
98
106
  export function duelProgram() {
99
107
  return <T extends DuelPluginRequirements>(client: T) => {
100
- return { ...client, duel: <DuelPlugin>{ accounts: { matchTicket: addSelfFetchFunctions(client, getMatchTicketCodec()), queue: addSelfFetchFunctions(client, getQueueCodec()), tenant: addSelfFetchFunctions(client, getTenantCodec()) }, instructions: { cancelTicket: input => addSelfPlanAndSendFunctions(client, getCancelTicketInstructionAsync(input)), closeTicket: input => addSelfPlanAndSendFunctions(client, getCloseTicketInstructionAsync(input)), commitTickets: input => addSelfPlanAndSendFunctions(client, getCommitTicketsInstruction({ ...input, payer: input.payer ?? client.payer })), createTicket: input => addSelfPlanAndSendFunctions(client, getCreateTicketInstructionAsync(input)), delegateQueue: input => addSelfPlanAndSendFunctions(client, getDelegateQueueInstructionAsync({ ...input, payer: input.payer ?? client.payer })), delegateTicket: input => addSelfPlanAndSendFunctions(client, getDelegateTicketInstructionAsync({ ...input, payer: input.payer ?? client.payer })), flushMatches: input => addSelfPlanAndSendFunctions(client, getFlushMatchesInstruction(input)), initializeQueue: input => addSelfPlanAndSendFunctions(client, getInitializeQueueInstructionAsync(input)), initializeTenant: input => addSelfPlanAndSendFunctions(client, getInitializeTenantInstructionAsync(input)), joinQueue: input => addSelfPlanAndSendFunctions(client, getJoinQueueInstructionAsync(input)), processUndelegation: input => addSelfPlanAndSendFunctions(client, getProcessUndelegationInstruction({ ...input, payer: input.payer ?? client.payer.address })) } } };
108
+ return { ...client, duel: <DuelPlugin>{ accounts: { matchTicket: addSelfFetchFunctions(client, getMatchTicketCodec()), queue: addSelfFetchFunctions(client, getQueueCodec()), tenant: addSelfFetchFunctions(client, getTenantCodec()) }, instructions: { cancelTicket: input => addSelfPlanAndSendFunctions(client, getCancelTicketInstructionAsync(input)), closeTicket: input => addSelfPlanAndSendFunctions(client, getCloseTicketInstructionAsync(input)), commitTickets: input => addSelfPlanAndSendFunctions(client, getCommitTicketsInstruction({ ...input, payer: input.payer ?? client.payer })), createTicket: input => addSelfPlanAndSendFunctions(client, getCreateTicketInstructionAsync(input)), delegateQueue: input => addSelfPlanAndSendFunctions(client, getDelegateQueueInstructionAsync({ ...input, payer: input.payer ?? client.payer })), delegateTicket: input => addSelfPlanAndSendFunctions(client, getDelegateTicketInstructionAsync({ ...input, payer: input.payer ?? client.payer })), flushMatches: input => addSelfPlanAndSendFunctions(client, getFlushMatchesInstruction(input)), initializeQueue: input => addSelfPlanAndSendFunctions(client, getInitializeQueueInstructionAsync(input)), initializeTenant: input => addSelfPlanAndSendFunctions(client, getInitializeTenantInstructionAsync(input)), joinQueue: input => addSelfPlanAndSendFunctions(client, getJoinQueueInstructionAsync(input)), processUndelegation: input => addSelfPlanAndSendFunctions(client, getProcessUndelegationInstruction({ ...input, payer: input.payer ?? client.payer.address })), setupQueuePermission: input => addSelfPlanAndSendFunctions(client, getSetupQueuePermissionInstructionAsync(input)), setupTicketPermission: input => addSelfPlanAndSendFunctions(client, getSetupTicketPermissionInstructionAsync(input)) } } };
101
109
  };
102
110
  }
103
111
 
package/src/player.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  import {
2
2
  createSolanaRpc,
3
+ AccountRole,
3
4
  type Address,
4
5
  type TransactionSigner,
5
6
  type Rpc,
6
7
  type SolanaRpcApi,
8
+ type Instruction,
7
9
  } from "@solana/kit";
8
10
  import {
9
11
  getCreateTicketInstructionAsync,
10
12
  getDelegateTicketInstructionAsync,
13
+ getSetupTicketPermissionInstructionAsync,
11
14
  getJoinQueueInstructionAsync,
12
15
  getCancelTicketInstructionAsync,
13
16
  getCloseTicketInstructionAsync,
@@ -69,6 +72,7 @@ export class MatchmakingPlayer {
69
72
  queue: Address,
70
73
  tenant: Address,
71
74
  playerData: Address,
75
+ callbackProgram?: Address,
72
76
  ): Promise<string> {
73
77
  const ix = await getJoinQueueInstructionAsync({
74
78
  queue,
@@ -76,7 +80,11 @@ export class MatchmakingPlayer {
76
80
  playerData,
77
81
  signer: this.signer,
78
82
  }, { programAddress: this.programId });
79
- return sendInstruction(this.rpc, ix, this.signer);
83
+ const ixFinal = callbackProgram
84
+ ? { ...ix, accounts: [...ix.accounts, { address: callbackProgram, role: 0 as const }] }
85
+ : ix;
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ return sendInstruction(this.rpc, ixFinal as any, this.signer);
80
88
  }
81
89
 
82
90
  async cancelTicket(tenant: Address): Promise<string> {
@@ -122,6 +130,69 @@ export class MatchmakingPlayer {
122
130
  return null;
123
131
  }
124
132
 
133
+ /**
134
+ * High-level: full matchmaking TEE entry flow.
135
+ * Creates ticket on L1, sets up permission PDA (so only player + queue authority can read it),
136
+ * delegates the permission PDA and ticket to TEE, then joins the queue.
137
+ * Use individual methods (createTicket, delegateTicket, joinQueue) as escape hatches if needed.
138
+ */
139
+ async enterQueue(
140
+ tenant: Address,
141
+ queue: Address,
142
+ playerData: Address,
143
+ teeRpc: Rpc<SolanaRpcApi>,
144
+ teeUrlWithToken: string,
145
+ validator?: Address,
146
+ callbackProgram?: Address,
147
+ ): Promise<Address> {
148
+ const player = this.signer.address as Address;
149
+ const ticketPda = await this.getTicketPda(player, tenant);
150
+
151
+ // 1. Create ticket on L1
152
+ await this.createTicket(tenant);
153
+
154
+ // 2. Create Permission PDA for the ticket (CPI from duel program with invoke_signed)
155
+ const permissionPda = await utils.derivePermissionPda(ticketPda);
156
+ const setupIx = await getSetupTicketPermissionInstructionAsync({
157
+ player: this.signer,
158
+ tenant,
159
+ permission: permissionPda,
160
+ permissionProgram: utils.PERMISSION_PROGRAM,
161
+ }, { programAddress: this.programId });
162
+ await sendInstruction(this.rpc, setupIx, this.signer);
163
+
164
+ // 3. Delegate Permission PDA to TEE (called on permission program, player signs)
165
+ const { delegationBuffer, delegationRecord, delegationMetadata } =
166
+ await utils.derivePermissionDelegationPdas(permissionPda);
167
+ const delegatePermIx: Instruction = {
168
+ programAddress: utils.PERMISSION_PROGRAM,
169
+ data: new Uint8Array([3, 0, 0, 0, 0, 0, 0, 0]),
170
+ accounts: [
171
+ { address: this.signer.address, role: AccountRole.WRITABLE_SIGNER },
172
+ { address: this.signer.address, role: AccountRole.READONLY_SIGNER },
173
+ { address: ticketPda, role: AccountRole.READONLY },
174
+ { address: permissionPda, role: AccountRole.WRITABLE },
175
+ { address: "11111111111111111111111111111111" as Address, role: AccountRole.READONLY },
176
+ { address: utils.PERMISSION_PROGRAM, role: AccountRole.READONLY },
177
+ { address: delegationBuffer, role: AccountRole.WRITABLE },
178
+ { address: delegationRecord, role: AccountRole.WRITABLE },
179
+ { address: delegationMetadata, role: AccountRole.WRITABLE },
180
+ { address: utils.DELEGATION_PROGRAM, role: AccountRole.READONLY },
181
+ ...(validator ? [{ address: validator, role: AccountRole.READONLY }] : []),
182
+ ],
183
+ };
184
+ await sendInstruction(this.rpc, delegatePermIx, this.signer);
185
+
186
+ // 4. Delegate ticket to TEE
187
+ await this.delegateTicket(player, tenant, validator);
188
+
189
+ // 5. Join the queue on TEE
190
+ const teeClient = new MatchmakingPlayer(teeRpc, this.signer, this.programId);
191
+ await teeClient.joinQueue(queue, tenant, playerData, callbackProgram);
192
+
193
+ return ticketPda;
194
+ }
195
+
125
196
  /** Create a new MatchmakingPlayer pointing at a TEE RPC endpoint. */
126
197
  withRpc(teeUrl: string): MatchmakingPlayer {
127
198
  return new MatchmakingPlayer(createSolanaRpc(teeUrl), this.signer, this.programId);
package/src/tee.ts CHANGED
@@ -45,35 +45,31 @@ export async function getAuthToken(
45
45
  }
46
46
 
47
47
  /**
48
- * Poll the TEE /permission endpoint until the given PDA has authorized users,
49
- * indicating delegation is active. Returns false on timeout (does not throw).
48
+ * Poll the TEE until the Permission PDA for the given account is active (authorizedUsers non-empty).
49
+ * This confirms the TEE has picked up the delegated Permission PDA and is enforcing access control.
50
+ * Returns true if active before timeout, false otherwise.
50
51
  */
51
- export async function waitUntilPermissionActive(
52
+ export async function waitForPermission(
52
53
  teeUrlWithToken: string,
53
- pda: Address,
54
- timeoutMs = 30000,
54
+ accountAddress: Address,
55
+ timeoutMs = 10000,
55
56
  ): Promise<boolean> {
56
- // Parse URL: "https://host/path?token=xxx" -> baseUrl="https://host/path", tokenParam="token=xxx"
57
- const [baseUrl, tokenParam] = teeUrlWithToken.replace("/?", "?").split("?");
58
- let permissionUrl: string;
59
- if (tokenParam) {
60
- permissionUrl = `${baseUrl}/permission?${tokenParam}&pubkey=${pda}`;
61
- } else {
62
- permissionUrl = `${baseUrl}/permission?pubkey=${pda}`;
63
- }
57
+ const [baseUrl, token] = teeUrlWithToken.replace("/?", "?").split("?");
58
+ const permUrl = token
59
+ ? `${baseUrl}/permission?${token}&pubkey=${accountAddress}`
60
+ : `${baseUrl}/permission?pubkey=${accountAddress}`;
64
61
 
65
- const start = Date.now();
66
- while (Date.now() - start < timeoutMs) {
62
+ const deadline = Date.now() + timeoutMs;
63
+ while (Date.now() < deadline) {
67
64
  try {
68
- const res = await fetch(permissionUrl);
69
- if (res.ok) {
70
- const { authorizedUsers } = (await res.json()) as { authorizedUsers?: unknown[] };
71
- if (authorizedUsers && authorizedUsers.length > 0) return true;
72
- }
65
+ const res = await fetch(permUrl);
66
+ const json = (await res.json()) as { authorizedUsers?: unknown[] | null };
67
+ if (json.authorizedUsers && json.authorizedUsers.length > 0) return true;
73
68
  } catch {
74
- // ignore transient errors, keep polling
69
+ // ignore transient errors
75
70
  }
76
- await new Promise((r) => setTimeout(r, 400));
71
+ await new Promise((r) => setTimeout(r, 500));
77
72
  }
78
73
  return false;
79
74
  }
75
+