|
@@ -11,6 +11,10 @@ import {
|
|
|
IdlAccount,
|
|
|
IdlAccountItem,
|
|
|
IdlAccounts,
|
|
|
+ IdlTypeDef,
|
|
|
+ IdlTypeDefStruct,
|
|
|
+ IdlTypeDefTyStruct,
|
|
|
+ IdlType,
|
|
|
} from "../idl.js";
|
|
|
import * as utf8 from "../utils/bytes/utf8.js";
|
|
|
import { TOKEN_PROGRAM_ID, ASSOCIATED_PROGRAM_ID } from "../utils/token.js";
|
|
@@ -50,6 +54,7 @@ export class AccountsResolver<IDL extends Idl, I extends AllInstructions<IDL>> {
|
|
|
private _programId: PublicKey,
|
|
|
private _idlIx: AllInstructions<IDL>,
|
|
|
_accountNamespace: AccountNamespace<IDL>,
|
|
|
+ private _idlTypes: IdlTypeDef[],
|
|
|
private _customResolver?: CustomAccountResolver<IDL>
|
|
|
) {
|
|
|
this._args = _args;
|
|
@@ -180,8 +185,9 @@ export class AccountsResolver<IDL extends Idl, I extends AllInstructions<IDL>> {
|
|
|
accountDescCasted.pda.seeds.length > 0 &&
|
|
|
!this.get([...path, accountDescName])
|
|
|
) {
|
|
|
- await this.autoPopulatePda(accountDescCasted, path);
|
|
|
- found += 1;
|
|
|
+ if (Boolean(await this.autoPopulatePda(accountDescCasted, path))) {
|
|
|
+ found += 1;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return found;
|
|
@@ -233,12 +239,19 @@ export class AccountsResolver<IDL extends Idl, I extends AllInstructions<IDL>> {
|
|
|
if (!accountDesc.pda || !accountDesc.pda.seeds)
|
|
|
throw new Error("Must have seeds");
|
|
|
|
|
|
- const seeds: Buffer[] = await Promise.all(
|
|
|
+ const seeds: (Buffer | undefined)[] = await Promise.all(
|
|
|
accountDesc.pda.seeds.map((seedDesc: IdlSeed) => this.toBuffer(seedDesc))
|
|
|
);
|
|
|
|
|
|
+ if (seeds.some((seed) => typeof seed == "undefined")) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
const programId = await this.parseProgramId(accountDesc);
|
|
|
- const [pubkey] = await PublicKey.findProgramAddress(seeds, programId);
|
|
|
+ const [pubkey] = await PublicKey.findProgramAddress(
|
|
|
+ seeds as Buffer[],
|
|
|
+ programId
|
|
|
+ );
|
|
|
|
|
|
this.set([...path, camelCase(accountDesc.name)], pubkey);
|
|
|
}
|
|
@@ -263,7 +276,7 @@ export class AccountsResolver<IDL extends Idl, I extends AllInstructions<IDL>> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private async toBuffer(seedDesc: IdlSeed): Promise<Buffer> {
|
|
|
+ private async toBuffer(seedDesc: IdlSeed): Promise<Buffer | undefined> {
|
|
|
switch (seedDesc.kind) {
|
|
|
case "const":
|
|
|
return this.toBufferConst(seedDesc);
|
|
@@ -276,17 +289,48 @@ export class AccountsResolver<IDL extends Idl, I extends AllInstructions<IDL>> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Recursively get the type at some path of either a primitive or a user defined struct.
|
|
|
+ */
|
|
|
+ private getType(type: IdlType, path: string[] = []): string {
|
|
|
+ if (path.length > 0 && (type as any).defined) {
|
|
|
+ const subType = this._idlTypes.find(
|
|
|
+ (t) => t.name === (type as any).defined
|
|
|
+ );
|
|
|
+ if (!subType) {
|
|
|
+ throw new Error(`Cannot find type ${(type as any).defined}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ const structType = subType.type as IdlTypeDefTyStruct; // enum not supported yet
|
|
|
+ const field = structType.fields.find((field) => field.name === path[0]);
|
|
|
+
|
|
|
+ return this.getType(field!.type, path.slice(1));
|
|
|
+ }
|
|
|
+
|
|
|
+ return type as string;
|
|
|
+ }
|
|
|
+
|
|
|
private toBufferConst(seedDesc: IdlSeed): Buffer {
|
|
|
- return this.toBufferValue(seedDesc.type, seedDesc.value);
|
|
|
+ return this.toBufferValue(
|
|
|
+ this.getType(seedDesc.type, (seedDesc.path || "").split(".").slice(1)),
|
|
|
+ seedDesc.value
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
- private async toBufferArg(seedDesc: IdlSeed): Promise<Buffer> {
|
|
|
+ private async toBufferArg(seedDesc: IdlSeed): Promise<Buffer | undefined> {
|
|
|
const argValue = this.argValue(seedDesc);
|
|
|
- return this.toBufferValue(seedDesc.type, argValue);
|
|
|
+ if (!argValue) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ return this.toBufferValue(
|
|
|
+ this.getType(seedDesc.type, (seedDesc.path || "").split(".").slice(1)),
|
|
|
+ argValue
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
private argValue(seedDesc: IdlSeed): any {
|
|
|
- const seedArgName = camelCase(seedDesc.path.split(".")[0]);
|
|
|
+ const split = seedDesc.path.split(".");
|
|
|
+ const seedArgName = camelCase(split[0]);
|
|
|
|
|
|
const idlArgPosition = this._idlIx.args.findIndex(
|
|
|
(argDesc: any) => argDesc.name === seedArgName
|
|
@@ -295,11 +339,18 @@ export class AccountsResolver<IDL extends Idl, I extends AllInstructions<IDL>> {
|
|
|
throw new Error(`Unable to find argument for seed: ${seedArgName}`);
|
|
|
}
|
|
|
|
|
|
- return this._args[idlArgPosition];
|
|
|
+ return split
|
|
|
+ .slice(1)
|
|
|
+ .reduce((curr, path) => (curr || {})[path], this._args[idlArgPosition]);
|
|
|
}
|
|
|
|
|
|
- private async toBufferAccount(seedDesc: IdlSeed): Promise<Buffer> {
|
|
|
+ private async toBufferAccount(
|
|
|
+ seedDesc: IdlSeed
|
|
|
+ ): Promise<Buffer | undefined> {
|
|
|
const accountValue = await this.accountValue(seedDesc);
|
|
|
+ if (!accountValue) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
return this.toBufferValue(seedDesc.type, accountValue);
|
|
|
}
|
|
|
|