@shyft-to/solana-transaction-parser
Version:
Tool for parsing arbitrary Solana transactions with IDL/custom parsers
232 lines • 7.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertLegacyIdlToV30 = void 0;
const sha256_1 = require("@noble/hashes/sha256");
const camelcase_1 = require("./camelcase");
function camelToUnderscore(key) {
const result = key.replace(/([A-Z])/g, " $1");
return result.split(" ").join("_").toLowerCase();
}
const snakeCase = camelToUnderscore;
function convertLegacyIdl(legacyIdl, programAddress) {
const address = programAddress ?? legacyIdl.metadata?.address;
if (!address) {
throw new Error("Program id missing in `idl.metadata.address` field");
}
return {
accounts: (legacyIdl.accounts || []).map(convertAccount),
address: address,
constants: (legacyIdl.constants || []).map(convertConst),
errors: legacyIdl.errors?.map(convertErrorCode) || [],
events: legacyIdl.events?.map(convertEvent) || [],
instructions: legacyIdl.instructions.map(convertInstruction),
metadata: {
name: legacyIdl.name,
version: legacyIdl.version,
spec: "0.1.0",
},
types: [
...(legacyIdl.types || []).map(convertTypeDef),
...(legacyIdl.accounts || []).map(convertTypeDef),
...(legacyIdl.events || []).map(convertEventToTypeDef),
],
};
}
function getDisc(prefix, name) {
const hash = (0, sha256_1.sha256)(`${prefix}:${name}`);
return Array.from(hash.slice(0, 8));
}
function convertInstruction(instruction) {
const name = instruction.name;
return {
accounts: instruction.accounts.map(convertInstructionAccount),
args: instruction.args.map(convertField),
discriminator: getDisc("global", snakeCase(name)),
name,
returns: instruction.returns ? convertType(instruction.returns) : undefined,
};
}
function convertAccount(account) {
return {
discriminator: getDisc("account", (0, camelcase_1.camelCase)(account.name, { preserveConsecutiveUppercase: true, pascalCase: true })),
name: account.name,
};
}
function convertTypeDef(typeDef) {
return {
name: typeDef.name,
type: convertTypeDefTy(typeDef.type),
};
}
function convertTypeDefTy(type) {
switch (type.kind) {
case "struct":
return {
fields: type.fields.map(convertField),
kind: "struct",
};
case "enum":
return {
kind: "enum",
variants: type.variants.map(convertEnumVariant),
};
case "alias":
return {
alias: convertType(type.value),
kind: "type",
};
}
}
function convertField(field) {
return {
name: field.name,
type: convertType(field.type),
};
}
function convertEnumVariant(variant) {
return {
fields: variant.fields ? convertEnumFields(variant.fields) : undefined,
name: variant.name,
};
}
function convertEnumFields(fields) {
if (Array.isArray(fields) && fields.length > 0 && typeof fields[0] === "object" && "type" in fields[0]) {
return fields.map(convertField);
}
else {
return fields.map((type) => convertType(type));
}
}
function convertEvent(event) {
return {
discriminator: getDisc("event", event.name),
name: event.name,
};
}
function convertErrorCode(error) {
return {
code: error.code,
msg: error.msg,
name: error.name,
};
}
function convertConst(constant) {
return {
name: constant.name,
type: convertType(constant.type),
value: constant.value,
};
}
function convertInstructionAccount(account) {
if ("accounts" in account) {
return convertInstructionAccounts(account);
}
else {
return {
docs: account.docs || [],
name: account.name,
optional: account.isOptional || false,
pda: account.pda ? convertPda(account.pda) : undefined,
relations: account.relations || [],
signer: account.isSigner || false,
writable: account.isMut || false,
};
}
}
function convertInstructionAccounts(accounts) {
return {
accounts: accounts.accounts.map(convertInstructionAccount),
name: accounts.name,
};
}
function convertPda(pda) {
return {
programId: pda.programId ? convertSeed(pda.programId) : undefined,
seeds: pda.seeds.map(convertSeed),
};
}
function convertSeed(seed) {
switch (seed.kind) {
case "const":
return { kind: "const", type: convertType(seed.type), value: seed.value };
case "arg":
return { kind: "arg", path: seed.path, type: convertType(seed.type) };
case "account":
return {
account: seed.account,
kind: "account",
path: seed.path,
type: convertType(seed.type),
};
}
}
function convertEventToTypeDef(event) {
return {
name: event.name,
type: {
fields: event.fields.map((field) => ({
name: field.name,
type: convertType(field.type),
})),
kind: "struct",
},
};
}
function convertType(type) {
if (typeof type === "string") {
return type === "publicKey" ? "pubkey" : type;
}
else if ("vec" in type) {
return { vec: convertType(type.vec) };
}
else if ("option" in type) {
return { option: convertType(type.option) };
}
else if ("defined" in type) {
return { defined: { generics: [], name: type.defined } };
}
else if ("array" in type) {
return { array: [convertType(type.array[0]), type.array[1]] };
}
else if ("generic" in type) {
return type;
}
else if ("definedWithTypeArgs" in type) {
return {
defined: {
generics: type.definedWithTypeArgs.args.map(convertDefinedTypeArg),
name: type.definedWithTypeArgs.name,
},
};
}
throw new Error(`Unsupported type: ${JSON.stringify(type)}`);
}
function convertDefinedTypeArg(arg) {
if ("generic" in arg) {
return { generic: arg.generic };
}
else if ("value" in arg) {
return { value: arg.value };
}
else if ("type" in arg) {
return { type: convertType(arg.type) };
}
throw new Error(`Unsupported defined type arg: ${JSON.stringify(arg)}`);
}
function convertLegacyIdlToV30(idl, programAddress) {
const spec = idl.metadata?.spec;
if (spec) {
switch (spec) {
case "0.1.0":
return idl;
default:
throw new Error(`IDL spec not supported: ${spec ?? ""}`);
}
}
else {
const formattedIdl = convertLegacyIdl(idl, programAddress);
return formattedIdl;
}
}
exports.convertLegacyIdlToV30 = convertLegacyIdlToV30;
//# sourceMappingURL=legacy.idl.converter.js.map