proof-of-take-sdk 3.0.7 → 3.0.9

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 (50) hide show
  1. package/dist/constants/season.d.ts +20 -17
  2. package/dist/constants/season.js +24 -18
  3. package/dist/idl/proof_of_take.json +132 -16
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/instructions/claimReferralPenaltyForWindow.d.ts +1 -1
  7. package/dist/instructions/claimReferralPenaltyForWindow.js +2 -1
  8. package/dist/instructions/claimWindowRewards.d.ts +1 -3
  9. package/dist/instructions/claimWindowRewards.js +4 -15
  10. package/dist/instructions/closeAuxiliaryAccounts.js +19 -12
  11. package/dist/instructions/confirmedPostOnX.d.ts +1 -1
  12. package/dist/instructions/confirmedPostOnX.js +5 -1
  13. package/dist/instructions/createMiztake.d.ts +1 -1
  14. package/dist/instructions/createMiztake.js +7 -3
  15. package/dist/instructions/initializeEscrowVault.js +5 -4
  16. package/dist/instructions/initializeRewardWindow.js +5 -4
  17. package/dist/instructions/initializeSeasonSettings.js +6 -7
  18. package/dist/instructions/initializeSeasonVault.js +6 -7
  19. package/dist/instructions/initializeStatistics.js +5 -5
  20. package/dist/instructions/joinSeason.d.ts +1 -1
  21. package/dist/instructions/joinSeason.js +20 -5
  22. package/dist/instructions/toggleSeasonPause.js +6 -7
  23. package/dist/instructions/updateSeasonAdmin.js +6 -7
  24. package/dist/instructions/viewSeasonMembershipStatus.d.ts +1 -1
  25. package/dist/instructions/viewSeasonMembershipStatus.js +1 -1
  26. package/dist/instructions/withdrawSeasonDeposit.d.ts +1 -1
  27. package/dist/instructions/withdrawSeasonDeposit.js +2 -1
  28. package/dist/types/accountTypes.d.ts +3 -1
  29. package/dist/types/proof_of_take.d.ts +132 -16
  30. package/dist/types.d.ts +4 -2
  31. package/dist/utils/accountConverters.js +1 -0
  32. package/dist/utils/accountUpdates.d.ts +3 -3
  33. package/dist/utils/accountUpdates.js +4 -3
  34. package/dist/utils/instructionResultHelpers.d.ts +7 -0
  35. package/dist/utils/instructionResultHelpers.js +9 -0
  36. package/dist/utils/pdas.d.ts +4 -4
  37. package/dist/utils/pdas.js +8 -7
  38. package/dist/utils/programErrors.d.ts +13 -0
  39. package/dist/utils/programErrors.js +47 -0
  40. package/dist/utils/remainingAccounts.d.ts +17 -0
  41. package/dist/utils/remainingAccounts.js +38 -0
  42. package/dist/utils/signerHelpers.d.ts +20 -0
  43. package/dist/utils/signerHelpers.js +64 -5
  44. package/dist/utils/tierPenalty.d.ts +2 -2
  45. package/dist/utils/tierPenalty.js +17 -16
  46. package/dist/utils/tierSeeds.d.ts +8 -0
  47. package/dist/utils/tierSeeds.js +14 -0
  48. package/dist/utils/transactionBuilder.d.ts +1 -0
  49. package/dist/utils/transactionBuilder.js +11 -9
  50. package/package.json +1 -1
@@ -15,6 +15,7 @@ const web3_js_1 = require("@solana/web3.js");
15
15
  const constants_1 = require("./constants");
16
16
  const conversions_1 = require("./conversions");
17
17
  const tierPenalty_1 = require("./tierPenalty");
18
+ const tierSeeds_1 = require("./tierSeeds");
18
19
  const conversions_2 = require("./conversions");
19
20
  /**
20
21
  * PDA (Program Derived Address) derivation helpers
@@ -61,11 +62,11 @@ function getSeasonPda(seasonNumber) {
61
62
  * seeds = ["season_membership", season_number_le_u64, user_pubkey_bytes, tier_u8]
62
63
  *
63
64
  * Tier mapping (u8):
64
- * 1 = copper, 2 = silver, 3 = gold, 4 = platinum, 5 = mithril
65
+ * 0 = copper, 1 = silver, 2 = gold, 3 = platinum, 4 = mithril
65
66
  *
66
67
  * @param seasonNumber - The season number
67
68
  * @param user - The user's public key
68
- * @param tier - Tier number (1..=5)
69
+ * @param tier - Tier number (0..=4)
69
70
  */
70
71
  function getSeasonMembershipPda(seasonNumber, user, tier) {
71
72
  const t = (0, tierPenalty_1.assertValidTierNumber)(tier);
@@ -74,7 +75,7 @@ function getSeasonMembershipPda(seasonNumber, user, tier) {
74
75
  Buffer.from("season_membership"),
75
76
  seasonBn.toArrayLike(Buffer, "le", 8),
76
77
  user.toBuffer(),
77
- Buffer.from([t]),
78
+ Buffer.from([(0, tierSeeds_1.toTierSeedByte)(t)]),
78
79
  ], constants_1.PROGRAM_ID);
79
80
  }
80
81
  /**
@@ -97,7 +98,7 @@ function getRewardWindowPda(seasonNumber, windowNumber) {
97
98
  *
98
99
  * @param seasonNumber - The season number
99
100
  * @param user - The user's public key
100
- * @param tier - Tier number (1..=5)
101
+ * @param tier - Tier number (0..=4)
101
102
  * @param windowNumber - The window number
102
103
  */
103
104
  function getUserWindowParticipationPda(seasonNumber, user, tier, windowNumber) {
@@ -107,7 +108,7 @@ function getUserWindowParticipationPda(seasonNumber, user, tier, windowNumber) {
107
108
  Buffer.from("user_window"),
108
109
  seasonBn.toArrayLike(Buffer, "le", 8),
109
110
  user.toBuffer(),
110
- Buffer.from([t]),
111
+ Buffer.from([(0, tierSeeds_1.toTierSeedByte)(t)]),
111
112
  windowNumber.toArrayLike(Buffer, "le", 8),
112
113
  ], constants_1.PROGRAM_ID);
113
114
  }
@@ -132,7 +133,7 @@ function getSeasonEscrowVaultPda(seasonNumber) {
132
133
  *
133
134
  * @param seasonNumber - The season number
134
135
  * @param referredUser - The referred user's public key (the user who missed)
135
- * @param tier - Tier number (1..=5)
136
+ * @param tier - Tier number (0..=4)
136
137
  * @param windowNumber - The window number
137
138
  */
138
139
  function getReferralPenaltyClaimPda(seasonNumber, referredUser, tier, windowNumber) {
@@ -142,7 +143,7 @@ function getReferralPenaltyClaimPda(seasonNumber, referredUser, tier, windowNumb
142
143
  Buffer.from(constants_1.REFERRAL_PENALTY_CLAIM_SEED),
143
144
  seasonBn.toArrayLike(Buffer, "le", 8),
144
145
  referredUser.toBuffer(),
145
- Buffer.from([t]),
146
+ Buffer.from([(0, tierSeeds_1.toTierSeedByte)(t)]),
146
147
  windowNumber.toArrayLike(Buffer, "le", 8),
147
148
  ], constants_1.PROGRAM_ID);
148
149
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Helpers for working with Solana/Anchor program errors.
3
+ *
4
+ * Goal: prefer checking errors by numeric code (stable) instead of string names
5
+ * (which may differ by casing between IDL vs generated TS types).
6
+ */
7
+ /**
8
+ * Try to extract a custom program error code (Anchor error code number).
9
+ *
10
+ * Returns `null` if the code cannot be determined.
11
+ */
12
+ export declare function getCustomProgramErrorCode(err: unknown): number | null;
13
+ export declare function isCustomProgramErrorCode(err: unknown, code: number): boolean;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * Helpers for working with Solana/Anchor program errors.
4
+ *
5
+ * Goal: prefer checking errors by numeric code (stable) instead of string names
6
+ * (which may differ by casing between IDL vs generated TS types).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getCustomProgramErrorCode = getCustomProgramErrorCode;
10
+ exports.isCustomProgramErrorCode = isCustomProgramErrorCode;
11
+ /**
12
+ * Try to extract a custom program error code (Anchor error code number).
13
+ *
14
+ * Returns `null` if the code cannot be determined.
15
+ */
16
+ function getCustomProgramErrorCode(err) {
17
+ const e = err;
18
+ // AnchorError shape (Anchor v0.30+ commonly nests under `.error`)
19
+ const anchorCode = e?.error?.errorCode?.number ??
20
+ e?.error?.errorCode?.code ??
21
+ e?.errorCode?.number ??
22
+ e?.errorCode?.code;
23
+ if (typeof anchorCode === "number")
24
+ return anchorCode;
25
+ // web3.js TransactionError: { InstructionError: [idx, { Custom: code }] }
26
+ const ixErr = e?.instructionError ?? e?.err ?? e?.error;
27
+ const instrErr = ixErr?.InstructionError ?? e?.InstructionError;
28
+ if (Array.isArray(instrErr) && instrErr.length >= 2) {
29
+ const detail = instrErr[1];
30
+ const custom = detail?.Custom ?? detail?.custom;
31
+ if (typeof custom === "number")
32
+ return custom;
33
+ }
34
+ // Fallback: parse from message/logs: "custom program error: 0x1793"
35
+ const text = (typeof e?.message === "string" ? e.message : "") +
36
+ "\n" +
37
+ (Array.isArray(e?.logs) ? e.logs.join("\n") : "");
38
+ const m = text.match(/custom program error:\s*0x([0-9a-f]+)/i);
39
+ if (m?.[1]) {
40
+ const code = Number.parseInt(m[1], 16);
41
+ return Number.isFinite(code) ? code : null;
42
+ }
43
+ return null;
44
+ }
45
+ function isCustomProgramErrorCode(err, code) {
46
+ return getCustomProgramErrorCode(err) === code;
47
+ }
@@ -0,0 +1,17 @@
1
+ import type { AccountMeta } from "@solana/web3.js";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ import type { BN } from "@coral-xyz/anchor";
4
+ import type { TierNumber } from "../types";
5
+ /**
6
+ * Build remaining accounts for joinSeason when a referrer is present.
7
+ *
8
+ * On-chain expects (when referrer != PublicKey.default):
9
+ * - remaining_accounts[0]: referrer SeasonMembership PDA (writable)
10
+ * - remaining_accounts[1]: referrer authority wallet (readonly)
11
+ * - remaining_accounts[2]: referrer MIZD ATA (writable; may be uninitialized and will be created)
12
+ */
13
+ export declare function getJoinSeasonRemainingAccounts(params: {
14
+ seasonNumber: BN;
15
+ tier: TierNumber;
16
+ referrer: PublicKey;
17
+ }): AccountMeta[];
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getJoinSeasonRemainingAccounts = getJoinSeasonRemainingAccounts;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const spl_token_1 = require("@solana/spl-token");
6
+ const pdas_1 = require("./pdas");
7
+ const constants_1 = require("./constants");
8
+ /**
9
+ * Build remaining accounts for joinSeason when a referrer is present.
10
+ *
11
+ * On-chain expects (when referrer != PublicKey.default):
12
+ * - remaining_accounts[0]: referrer SeasonMembership PDA (writable)
13
+ * - remaining_accounts[1]: referrer authority wallet (readonly)
14
+ * - remaining_accounts[2]: referrer MIZD ATA (writable; may be uninitialized and will be created)
15
+ */
16
+ function getJoinSeasonRemainingAccounts(params) {
17
+ if (params.referrer.equals(web3_js_1.PublicKey.default))
18
+ return [];
19
+ const [referrerSeasonMembership] = (0, pdas_1.getSeasonMembershipPda)(params.seasonNumber, params.referrer, params.tier);
20
+ const referrerMizdAta = (0, spl_token_1.getAssociatedTokenAddressSync)(constants_1.MIZD_TOKEN_MINT, params.referrer);
21
+ return [
22
+ {
23
+ pubkey: referrerSeasonMembership,
24
+ isWritable: true,
25
+ isSigner: false,
26
+ },
27
+ {
28
+ pubkey: params.referrer,
29
+ isWritable: false,
30
+ isSigner: false,
31
+ },
32
+ {
33
+ pubkey: referrerMizdAta,
34
+ isWritable: true,
35
+ isSigner: false,
36
+ },
37
+ ];
38
+ }
@@ -7,6 +7,26 @@ export interface SignerInfo {
7
7
  publicKey: PublicKey;
8
8
  role: SignerRole;
9
9
  }
10
+ /**
11
+ * Resolve fee payer for this SDK.
12
+ *
13
+ * Policy:
14
+ * - If `feePayer` is provided, use it.
15
+ * - Else if an instruction-specific `admin` key is provided, use it.
16
+ * - Else fall back to global `ADMIN_PUBLIC_KEY`.
17
+ */
18
+ export declare function resolveFeePayer(params?: {
19
+ feePayer?: PublicKey | undefined;
20
+ admin?: PublicKey | undefined;
21
+ }): PublicKey;
22
+ /** Back-compat alias (admin pays by default). */
23
+ export declare function getDefaultFeePayer(feePayer?: PublicKey): PublicKey;
24
+ export declare const asAdminSigner: (publicKey: PublicKey) => SignerInfo;
25
+ export declare const asUserSigner: (publicKey: PublicKey) => SignerInfo;
26
+ export declare const asClaimantSigner: (publicKey: PublicKey) => SignerInfo;
27
+ export declare const asCurrentAdminSigner: (publicKey: PublicKey) => SignerInfo;
28
+ export declare const asFeePayerSigner: (publicKey: PublicKey) => SignerInfo;
29
+ export declare const asPayerSigner: (publicKey: PublicKey) => SignerInfo;
10
30
  /**
11
31
  * Build signers array with optional fee payer
12
32
  * Automatically deduplicates if fee payer is already in required signers
@@ -1,6 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asPayerSigner = exports.asFeePayerSigner = exports.asCurrentAdminSigner = exports.asClaimantSigner = exports.asUserSigner = exports.asAdminSigner = void 0;
4
+ exports.resolveFeePayer = resolveFeePayer;
5
+ exports.getDefaultFeePayer = getDefaultFeePayer;
3
6
  exports.buildSigners = buildSigners;
7
+ const constants_1 = require("./constants");
8
+ /**
9
+ * Resolve fee payer for this SDK.
10
+ *
11
+ * Policy:
12
+ * - If `feePayer` is provided, use it.
13
+ * - Else if an instruction-specific `admin` key is provided, use it.
14
+ * - Else fall back to global `ADMIN_PUBLIC_KEY`.
15
+ */
16
+ function resolveFeePayer(params) {
17
+ return params?.feePayer ?? params?.admin ?? constants_1.ADMIN_PUBLIC_KEY;
18
+ }
19
+ /** Back-compat alias (admin pays by default). */
20
+ function getDefaultFeePayer(feePayer) {
21
+ return resolveFeePayer({ feePayer });
22
+ }
23
+ // ---- Signer constructors (to avoid ad-hoc role strings) ----
24
+ const asAdminSigner = (publicKey) => ({
25
+ publicKey,
26
+ role: "admin",
27
+ });
28
+ exports.asAdminSigner = asAdminSigner;
29
+ const asUserSigner = (publicKey) => ({
30
+ publicKey,
31
+ role: "user",
32
+ });
33
+ exports.asUserSigner = asUserSigner;
34
+ const asClaimantSigner = (publicKey) => ({
35
+ publicKey,
36
+ role: "claimant",
37
+ });
38
+ exports.asClaimantSigner = asClaimantSigner;
39
+ const asCurrentAdminSigner = (publicKey) => ({
40
+ publicKey,
41
+ role: "currentAdmin",
42
+ });
43
+ exports.asCurrentAdminSigner = asCurrentAdminSigner;
44
+ const asFeePayerSigner = (publicKey) => ({
45
+ publicKey,
46
+ role: "feePayer",
47
+ });
48
+ exports.asFeePayerSigner = asFeePayerSigner;
49
+ const asPayerSigner = (publicKey) => ({
50
+ publicKey,
51
+ role: "payer",
52
+ });
53
+ exports.asPayerSigner = asPayerSigner;
4
54
  /**
5
55
  * Build signers array with optional fee payer
6
56
  * Automatically deduplicates if fee payer is already in required signers
@@ -11,11 +61,20 @@ exports.buildSigners = buildSigners;
11
61
  */
12
62
  function buildSigners(requiredSigners, feePayer) {
13
63
  const signers = [...requiredSigners];
14
- if (feePayer) {
15
- const alreadyIncluded = signers.some((s) => s.publicKey.equals(feePayer));
16
- if (!alreadyIncluded) {
17
- signers.push({ publicKey: feePayer, role: "feePayer" });
18
- }
64
+ if (!feePayer) {
65
+ return signers;
66
+ }
67
+ // If fee payer is already among required signers (e.g. admin), move that signer to the front
68
+ // while preserving its original role. This ensures builders that default to signers[0] will
69
+ // still behave correctly, and avoids requiring a separate "feePayer" wallet mapping.
70
+ const existingIdx = signers.findIndex((s) => s.publicKey.equals(feePayer));
71
+ if (existingIdx >= 0) {
72
+ const existing = signers.splice(existingIdx, 1)[0];
73
+ signers.unshift(existing);
74
+ return signers;
19
75
  }
76
+ // Otherwise, include an explicit fee payer signer (callers must provide a wallet for role "feePayer").
77
+ const role = feePayer.equals(constants_1.ADMIN_PUBLIC_KEY) ? "admin" : "feePayer";
78
+ signers.unshift({ publicKey: feePayer, role });
20
79
  return signers;
21
80
  }
@@ -1,11 +1,11 @@
1
1
  import { BN } from "@coral-xyz/anchor";
2
2
  import { SeasonDepositTier, TierNumber } from "../types";
3
3
  /**
4
- * Validate and normalize a tier number (1..=5).
4
+ * Validate and normalize a tier number (0..=4).
5
5
  */
6
6
  export declare function assertValidTierNumber(tier: number): TierNumber;
7
7
  /**
8
- * Convert numeric tier (1..=5) to the Anchor enum representation.
8
+ * Convert numeric tier (0..=4) to the Anchor enum representation.
9
9
  */
10
10
  export declare function tierNumberToDepositTier(tier: number): SeasonDepositTier;
11
11
  /**
@@ -3,31 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertValidTierNumber = assertValidTierNumber;
4
4
  exports.tierNumberToDepositTier = tierNumberToDepositTier;
5
5
  exports.getTierPenaltyPerWindow = getTierPenaltyPerWindow;
6
- const anchor_1 = require("@coral-xyz/anchor");
7
6
  const depositTier_1 = require("./depositTier");
7
+ const season_1 = require("../constants/season");
8
8
  /**
9
- * Validate and normalize a tier number (1..=5).
9
+ * Validate and normalize a tier number (0..=4).
10
10
  */
11
11
  function assertValidTierNumber(tier) {
12
- if (!Number.isInteger(tier) || tier < 1 || tier > 5) {
13
- throw new Error("Invalid tier: must be an integer between 1 and 5");
12
+ if (!Number.isInteger(tier) || tier < 0 || tier > 4) {
13
+ throw new Error("Invalid tier: must be an integer between 0 and 4");
14
14
  }
15
15
  return tier;
16
16
  }
17
17
  /**
18
- * Convert numeric tier (1..=5) to the Anchor enum representation.
18
+ * Convert numeric tier (0..=4) to the Anchor enum representation.
19
19
  */
20
20
  function tierNumberToDepositTier(tier) {
21
21
  switch (assertValidTierNumber(tier)) {
22
- case 1:
22
+ case 0:
23
23
  return { copper: {} };
24
- case 2:
24
+ case 1:
25
25
  return { silver: {} };
26
- case 3:
26
+ case 2:
27
27
  return { gold: {} };
28
- case 4:
28
+ case 3:
29
29
  return { platinum: {} };
30
- case 5:
30
+ case 4:
31
31
  return { mithril: {} };
32
32
  }
33
33
  // unreachable
@@ -40,17 +40,18 @@ function tierNumberToDepositTier(tier) {
40
40
  * to mirror on-chain accounting (refund vs bonus portions).
41
41
  */
42
42
  function getTierPenaltyPerWindow(tier) {
43
- // Base units (7 decimals): 1 MIZD = 10_000_000
43
+ // Base units (7 decimals): 1 MIZD = MIZD_DECIMALS
44
+ void season_1.MIZD_DECIMALS; // doc-only; keep TS/ESLint from flagging as unused in some configs
44
45
  switch ((0, depositTier_1.getDepositTierName)(tier)) {
45
46
  case "copper":
46
- return new anchor_1.BN(1000000); // 0.1 MIZD
47
+ return season_1.MIZD_DECIMALS_BN.divn(10); // 0.1 MIZD
47
48
  case "silver":
48
- return new anchor_1.BN(10000000); // 1 MIZD
49
+ return season_1.MIZD_DECIMALS_BN; // 1 MIZD
49
50
  case "gold":
50
- return new anchor_1.BN(100000000); // 10 MIZD
51
+ return season_1.MIZD_DECIMALS_BN.muln(10); // 10 MIZD
51
52
  case "platinum":
52
- return new anchor_1.BN(1000000000); // 100 MIZD
53
+ return season_1.MIZD_DECIMALS_BN.muln(100); // 100 MIZD
53
54
  case "mithril":
54
- return new anchor_1.BN(10000000000); // 1,000 MIZD
55
+ return season_1.MIZD_DECIMALS_BN.muln(1000); // 1,000 MIZD
55
56
  }
56
57
  }
@@ -0,0 +1,8 @@
1
+ import type { TierNumber } from "../types";
2
+ /**
3
+ * Canonical tier encoding used for PDA seeds across the program.
4
+ *
5
+ * IMPORTANT: The tier byte is part of PDA seeds for several accounts (e.g. SeasonMembership,
6
+ * UserWindowParticipation, ReferralPenaltyClaim). Changing this mapping changes addresses.
7
+ */
8
+ export declare function toTierSeedByte(tier: TierNumber): number;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toTierSeedByte = toTierSeedByte;
4
+ /**
5
+ * Canonical tier encoding used for PDA seeds across the program.
6
+ *
7
+ * IMPORTANT: The tier byte is part of PDA seeds for several accounts (e.g. SeasonMembership,
8
+ * UserWindowParticipation, ReferralPenaltyClaim). Changing this mapping changes addresses.
9
+ */
10
+ function toTierSeedByte(tier) {
11
+ // Currently the TierNumber union is already the canonical seed byte (0..4),
12
+ // but keeping this indirection makes future tier encoding changes a 1-line edit.
13
+ return tier;
14
+ }
@@ -35,6 +35,7 @@ export declare class TransactionBuilder {
35
35
  private connection;
36
36
  private wallets;
37
37
  constructor(connection: Connection, wallets: Map<string, WalletAdapter>);
38
+ private getFeePayerFromSigners;
38
39
  /**
39
40
  * Build a transaction from instructions
40
41
  */
@@ -12,6 +12,14 @@ class TransactionBuilder {
12
12
  this.connection = connection;
13
13
  this.wallets = wallets;
14
14
  }
15
+ getFeePayerFromSigners(signers) {
16
+ const explicit = signers.find((s) => s.role === "feePayer")?.publicKey;
17
+ const fallback = signers[0]?.publicKey;
18
+ if (!explicit && !fallback) {
19
+ throw new Error("At least one signer required");
20
+ }
21
+ return explicit ?? fallback;
22
+ }
15
23
  /**
16
24
  * Build a transaction from instructions
17
25
  */
@@ -60,11 +68,8 @@ class TransactionBuilder {
60
68
  * Build, sign, and send a transaction
61
69
  */
62
70
  async buildSignAndSend(instructions, signers, options) {
63
- // Determine fee payer (first signer by default)
64
- const feePayer = signers[0]?.publicKey;
65
- if (!feePayer) {
66
- throw new Error("At least one signer required");
67
- }
71
+ // Determine fee payer (explicit feePayer role preferred; else first signer)
72
+ const feePayer = this.getFeePayerFromSigners(signers);
68
73
  // Build transaction
69
74
  const transaction = await this.buildTransaction(instructions, feePayer, options);
70
75
  // Sign transaction
@@ -84,10 +89,7 @@ class TransactionBuilder {
84
89
  * Simulate a transaction without sending
85
90
  */
86
91
  async simulate(instructions, signers) {
87
- const feePayer = signers[0]?.publicKey;
88
- if (!feePayer) {
89
- throw new Error("At least one signer required for simulation");
90
- }
92
+ const feePayer = this.getFeePayerFromSigners(signers);
91
93
  const transaction = await this.buildTransaction(instructions, feePayer);
92
94
  try {
93
95
  const simulation = await this.connection.simulateTransaction(transaction);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proof-of-take-sdk",
3
- "version": "3.0.7",
3
+ "version": "3.0.9",
4
4
  "description": "TypeScript SDK for Proof of Take Solana program",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",