@ledgerhq/device-signer-kit-solana 0.0.0-develop-20250627001242 → 0.0.0-develop-20250628001217
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/lib/cjs/internal/app-binder/services/TransactionInspector.js +2 -2
- package/lib/cjs/internal/app-binder/services/TransactionInspector.js.map +3 -3
- package/lib/cjs/internal/app-binder/services/TransactionInspector.test.js +1 -1
- package/lib/cjs/internal/app-binder/services/TransactionInspector.test.js.map +3 -3
- package/lib/esm/internal/app-binder/services/TransactionInspector.js +3 -3
- package/lib/esm/internal/app-binder/services/TransactionInspector.js.map +3 -3
- package/lib/esm/internal/app-binder/services/TransactionInspector.test.js +1 -1
- package/lib/esm/internal/app-binder/services/TransactionInspector.test.js.map +3 -3
- package/lib/types/internal/app-binder/services/TransactionInspector.d.ts +1 -2
- package/lib/types/internal/app-binder/services/TransactionInspector.d.ts.map +1 -1
- package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
- package/package.json +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`+
|
|
1
|
+
"use strict";var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var I=(c,e)=>{for(var s in e)d(c,s,{get:e[s],enumerable:!0})},f=(c,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of T(e))!A.call(c,a)&&a!==s&&d(c,a,{get:()=>e[a],enumerable:!(n=m(e,a))||n.enumerable});return c};var g=c=>f(d({},"__esModule",{value:!0}),c);var b={};I(b,{SolanaTransactionTypes:()=>y,TransactionInspector:()=>k});module.exports=g(b);var r=require("@solana/spl-token"),i=require("@solana/web3.js"),p=require("buffer"),y=(s=>(s.STANDARD="Standard",s.SPL="SPL",s))(y||{});class k{constructor(e){this.rawTransactionBytes=e}inspectTransactionType(){try{const e=this.extractMessage(this.rawTransactionBytes);for(const s of e.compiledInstructions){const n=e.staticAccountKeys[s.programIdIndex];if(!n.equals(r.TOKEN_PROGRAM_ID))continue;const a=new i.TransactionInstruction({programId:n,keys:s.accountKeyIndexes.map(t=>({pubkey:e.staticAccountKeys[t],isSigner:e.isAccountSigner(t),isWritable:e.isAccountWritable(t)})),data:p.Buffer.from(s.data)});switch(a.data[0]){case r.TokenInstruction.Transfer:{const{keys:{destination:t}}=(0,r.decodeTransferInstruction)(a);return{transactionType:"SPL",data:{tokenAddress:t.pubkey.toBase58()}}}case r.TokenInstruction.TransferChecked:{const{keys:{destination:t}}=(0,r.decodeTransferCheckedInstruction)(a);return{transactionType:"SPL",data:{tokenAddress:t.pubkey.toBase58()}}}case r.TokenInstruction.InitializeAccount:{const{keys:{account:t,mint:o}}=(0,r.decodeInitializeAccountInstruction)(a);return{transactionType:"SPL",data:{createATA:{address:t.pubkey.toBase58(),mintAddress:o.pubkey.toBase58()}}}}default:continue}}return{transactionType:"Standard",data:{}}}catch{return{transactionType:"Standard",data:{}}}}extractMessage(e){const s=[];try{return i.VersionedTransaction.deserialize(e).message}catch(n){s.push(n.message)}try{return i.VersionedMessage.deserialize(e)}catch(n){s.push(n.message)}try{const n=i.Transaction.from(e),a=[n.feePayer,...n.instructions.flatMap(t=>t.keys.map(o=>o.pubkey))],u=Array.from(new Map(a.filter(Boolean).map(t=>[t.toBase58(),t])).values());return{compiledInstructions:n.instructions.map(t=>({programIdIndex:u.findIndex(o=>o.equals(t.programId)),accountKeyIndexes:t.keys.map(o=>u.findIndex(l=>l.equals(o.pubkey))),data:t.data})),staticAccountKeys:u,isAccountSigner:t=>n.signatures.some(o=>o.publicKey.equals(u[t])),isAccountWritable:()=>!0}}catch(n){s.push(n.message)}throw new Error(`Invalid transaction payload \u2013 all deserializers failed:
|
|
2
|
+
`+s.map((n,a)=>`${a+1}) ${n}`).join(`
|
|
3
3
|
`))}}0&&(module.exports={SolanaTransactionTypes,TransactionInspector});
|
|
4
4
|
//# sourceMappingURL=TransactionInspector.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/services/TransactionInspector.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,4BAAAE,EAAA,yBAAAC,IAAA,eAAAC,EAAAJ,GAAA,IAAAK,
|
|
6
|
-
"names": ["TransactionInspector_exports", "__export", "SolanaTransactionTypes", "TransactionInspector", "__toCommonJS", "import_spl_token", "import_web3", "import_buffer", "rawTransactionBytes", "message", "
|
|
4
|
+
"sourcesContent": ["import {\n decodeInitializeAccountInstruction,\n decodeTransferCheckedInstruction,\n decodeTransferInstruction,\n TOKEN_PROGRAM_ID,\n TokenInstruction,\n} from \"@solana/spl-token\";\nimport {\n type PublicKey,\n Transaction,\n TransactionInstruction,\n VersionedMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { Buffer } from \"buffer\";\n\nexport enum SolanaTransactionTypes {\n STANDARD = \"Standard\",\n SPL = \"SPL\",\n}\nexport interface TxInspectorResult {\n transactionType: SolanaTransactionTypes;\n data: {\n tokenAddress?: string;\n createATA?: {\n address: string;\n mintAddress: string;\n };\n };\n}\n\nexport class TransactionInspector {\n constructor(private readonly rawTransactionBytes: Uint8Array) {}\n\n public inspectTransactionType(): TxInspectorResult {\n try {\n const message = this.extractMessage(this.rawTransactionBytes);\n\n for (const ixMeta of message.compiledInstructions) {\n const programId = message.staticAccountKeys[ixMeta.programIdIndex]!;\n if (!programId.equals(TOKEN_PROGRAM_ID)) continue;\n\n const instruction = new TransactionInstruction({\n programId,\n keys: ixMeta.accountKeyIndexes.map((i) => ({\n pubkey: message.staticAccountKeys[i]!,\n isSigner: message.isAccountSigner(i),\n isWritable: message.isAccountWritable(i),\n })),\n data: Buffer.from(ixMeta.data),\n });\n\n const instructionType = instruction.data[0];\n switch (instructionType) {\n case TokenInstruction.Transfer: {\n const {\n keys: { destination },\n } = decodeTransferInstruction(instruction);\n return {\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: destination.pubkey.toBase58() },\n };\n }\n case TokenInstruction.TransferChecked: {\n const {\n keys: { destination },\n } = decodeTransferCheckedInstruction(instruction);\n return {\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: destination.pubkey.toBase58() },\n };\n }\n case TokenInstruction.InitializeAccount: {\n const {\n keys: { account, mint },\n } = decodeInitializeAccountInstruction(instruction);\n return {\n transactionType: SolanaTransactionTypes.SPL,\n data: {\n createATA: {\n address: account.pubkey.toBase58(),\n mintAddress: mint.pubkey.toBase58(),\n },\n },\n };\n }\n default:\n continue;\n }\n }\n\n return {\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n };\n } catch {\n return {\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n };\n }\n }\n\n private extractMessage(rawBytes: Uint8Array): VersionedMessage {\n const errors: string[] = [];\n try {\n return VersionedTransaction.deserialize(rawBytes).message;\n } catch (e) {\n errors.push((e as Error).message);\n }\n\n try {\n return VersionedMessage.deserialize(rawBytes);\n } catch (e) {\n errors.push((e as Error).message);\n }\n\n try {\n const tx = Transaction.from(rawBytes);\n const allKeys = [\n tx.feePayer,\n ...tx.instructions.flatMap((ix) => ix.keys.map((k) => k.pubkey)),\n ];\n\n const staticAccountKeys = Array.from(\n new Map(\n (allKeys.filter(Boolean) as PublicKey[]).map((pk) => [\n pk.toBase58(),\n pk,\n ]),\n ).values(),\n );\n\n interface CustomCompiledInstruction {\n programIdIndex: number;\n accountKeyIndexes: number[];\n data: Uint8Array;\n }\n\n return {\n compiledInstructions: tx.instructions.map(\n (ix): CustomCompiledInstruction => ({\n programIdIndex: staticAccountKeys.findIndex((k) =>\n k.equals(ix.programId),\n ),\n accountKeyIndexes: ix.keys.map((k) =>\n staticAccountKeys.findIndex((s) => s.equals(k.pubkey)),\n ),\n data: ix.data,\n }),\n ),\n staticAccountKeys,\n isAccountSigner: (i: number) =>\n tx.signatures.some((sig) =>\n sig.publicKey.equals(staticAccountKeys[i]!),\n ),\n isAccountWritable: () => true,\n } as unknown as VersionedMessage;\n } catch (e) {\n errors.push((e as Error).message);\n }\n\n throw new Error(\n \"Invalid transaction payload \u2013 all deserializers failed:\\n\" +\n errors.map((m, i) => `${i + 1}) ${m}`).join(\"\\n\"),\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["TransactionInspector_exports", "__export", "SolanaTransactionTypes", "TransactionInspector", "__toCommonJS", "import_spl_token", "import_web3", "import_buffer", "rawTransactionBytes", "message", "ixMeta", "programId", "instruction", "i", "destination", "account", "mint", "rawBytes", "errors", "e", "tx", "allKeys", "ix", "k", "staticAccountKeys", "pk", "s", "sig", "m"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var T=Object.create;var d=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var m=(e,t,r,c)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of A(t))!g.call(e,n)&&n!==r&&d(e,n,{get:()=>t[n],enumerable:!(c=b(t,n))||c.enumerable});return e};var K=(e,t,r)=>(r=e!=null?T(f(e)):{},m(t||!e||!e.__esModule?d(r,"default",{value:e,enumerable:!0}):r,e));var p=require("@solana/spl-token"),a=require("@solana/web3.js"),u=K(require("bs58")),s=require("vitest"),o=require("./TransactionInspector");const l=u.default.encode(new Uint8Array(32).fill(1));(0,s.describe)("TransactionInspector",()=>{(0,s.it)("falls back to STANDARD for a plain SystemProgram transfer",()=>{const e=a.Keypair.generate(),t=a.Keypair.generate().publicKey,r=new a.Transaction().add(a.SystemProgram.transfer({fromPubkey:e.publicKey,toPubkey:t,lamports:1e3}));r.recentBlockhash=l,r.feePayer=e.publicKey,r.sign(e);const c=r.serialize(),n=new o.TransactionInspector(c).inspectTransactionType();(0,s.expect)(n.transactionType).toBe(o.SolanaTransactionTypes.STANDARD),(0,s.expect)(n.data).toEqual({})}),(0,s.it)("detects an SPL Transfer and returns the destination address",()=>{const e=a.Keypair.generate(),t=a.Keypair.generate().publicKey,r=a.Keypair.generate().publicKey,c=e.publicKey,n=new a.Transaction().add((0,p.createTransferInstruction)(t,r,c,42n,[],p.TOKEN_PROGRAM_ID));n.recentBlockhash=l,n.feePayer=e.publicKey,n.sign(e);const i=new o.TransactionInspector(n.serialize()).inspectTransactionType();(0,s.expect)(i.transactionType).toBe(o.SolanaTransactionTypes.SPL),(0,s.expect)(i.data.tokenAddress).toBe(r.toBase58())}),(0,s.it)("detects an SPL TransferChecked and returns the destination address",()=>{const e=a.Keypair.generate(),t=a.Keypair.generate().publicKey,r=a.Keypair.generate().publicKey,c=a.Keypair.generate().publicKey,n=e.publicKey,i=new a.Transaction().add((0,p.createTransferCheckedInstruction)(r,t,c,n,123n,0,[],p.TOKEN_PROGRAM_ID));i.recentBlockhash=l,i.feePayer=e.publicKey,i.sign(e);const y=new o.TransactionInspector(i.serialize()).inspectTransactionType();(0,s.expect)(y.transactionType).toBe(o.SolanaTransactionTypes.SPL),(0,s.expect)(y.data.tokenAddress).toBe(c.toBase58())}),(0,s.it)("detects an SPL InitializeAccount and returns the new ATA and mint",()=>{const e=a.Keypair.generate(),t=a.Keypair.generate().publicKey,r=a.Keypair.generate().publicKey,c=e.publicKey,n=new a.Transaction().add((0,p.createInitializeAccountInstruction)(r,t,c,p.TOKEN_PROGRAM_ID));n.recentBlockhash=l,n.feePayer=e.publicKey,n.sign(e);const i=new o.TransactionInspector(n.serialize()).inspectTransactionType();(0,s.expect)(i.transactionType).toBe(o.SolanaTransactionTypes.SPL),(0,s.expect)(i.data.createATA).toEqual({address:r.toBase58(),mintAddress:t.toBase58()})}),(0,s.it)("falls back to STANDARD if the payload is unparseable",()=>{const e=new Uint8Array([0,1,2,3,4,5]),t=new o.TransactionInspector(e).inspectTransactionType();(0,s.expect)(t.transactionType).toBe(o.SolanaTransactionTypes.STANDARD),(0,s.expect)(t.data).toEqual({})})});
|
|
2
2
|
//# sourceMappingURL=TransactionInspector.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/services/TransactionInspector.test.ts"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as splToken from \"@solana/spl-token\";\nimport {\n Keypair,\n type PublicKey,\n SystemProgram,\n Transaction,\n type TransactionInstruction,\n VersionedMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\n\nimport {\n SolanaTransactionTypes,\n TransactionInspector,\n} from \"./TransactionInspector\";\n\nfunction makeFakeMessage(opts: {\n compiledInstructions: Array<{\n programIdIndex: number;\n accountKeyIndexes: number[];\n data: Uint8Array | number[] | Buffer;\n }>;\n staticAccountKeys: PublicKey[];\n}): VersionedMessage {\n return {\n compiledInstructions: opts.compiledInstructions.map((ix) => ({\n ...ix,\n data:\n ix.data instanceof Uint8Array\n ? ix.data\n : typeof Buffer !== \"undefined\" && ix.data instanceof Buffer\n ? ix.data\n : new Uint8Array(ix.data as number[]),\n })),\n staticAccountKeys: opts.staticAccountKeys,\n isAccountSigner: (_: number) => false,\n isAccountWritable: (_: number) => false,\n } as any;\n}\n\nvi.mock(\"@solana/spl-token\", async () => {\n const actual = await vi.importActual<any>(\"@solana/spl-token\");\n return {\n ...actual,\n decodeInstruction: vi.fn(),\n getAssociatedTokenAddress: vi.fn(),\n TOKEN_PROGRAM_ID: actual.TOKEN_PROGRAM_ID,\n };\n});\nconst { decodeInstruction, getAssociatedTokenAddress, TOKEN_PROGRAM_ID } =\n splToken as any;\n\ndescribe(\"TransactionInspector\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n it(\"returns STANDARD when no SPL instructions are found\", async () => {\n // given\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(\n makeFakeMessage({ compiledInstructions: [], staticAccountKeys: [] }),\n );\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n });\n });\n\n it(\"ignores instructions not targeting TOKEN_PROGRAM_ID\", async () => {\n // given\n const fakePk = Keypair.generate().publicKey;\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [1],\n data: new Uint8Array([1]),\n },\n ],\n staticAccountKeys: [fakePk, Keypair.generate().publicKey],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res.transactionType).toBe(SolanaTransactionTypes.STANDARD);\n });\n\n it(\"skips a first bad decodeInstruction and succeeds on the next\", async () => {\n // given\n const dest = Keypair.generate().publicKey;\n const other = Keypair.generate().publicKey;\n\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [0, 1, 2],\n data: new Uint8Array([0]),\n },\n {\n programIdIndex: 0,\n accountKeyIndexes: [0, 1, 2],\n data: new Uint8Array([0]),\n },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, other, dest],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction\n .mockReturnValueOnce(new Error(\"bad\"))\n .mockReturnValueOnce({ data: { amount: 7 } });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: dest.toBase58() },\n });\n });\n\n it(\"converts Buffer or number[] data into Uint8Array before decoding\", async () => {\n // given\n const dest = Keypair.generate().publicKey;\n const other = Keypair.generate().publicKey;\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [0, 1, 2],\n data: Buffer.from([5, 6, 7]),\n },\n { programIdIndex: 0, accountKeyIndexes: [0, 1, 2], data: [8, 9, 10] },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, other, dest],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction\n .mockReturnValueOnce(new Error(\"nope\"))\n .mockImplementation((ix: TransactionInstruction) => {\n expect(ix.data).toBeInstanceOf(Uint8Array);\n return { data: { amount: 21 } };\n });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res.data).toEqual({ tokenAddress: dest.toBase58() });\n });\n\n it(\"detects TransferChecked with existing ATA\", async () => {\n // given\n const mint = Keypair.generate().publicKey;\n const auth = Keypair.generate().publicKey;\n const ata = Keypair.generate().publicKey;\n getAssociatedTokenAddress.mockResolvedValue(ata);\n\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [1, 2, 3, 4],\n data: new Uint8Array([3]),\n },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, auth, ata, ata, mint],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction.mockReturnValue({\n data: { mint, authority: auth, source: ata, destination: ata },\n });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: ata.toBase58() },\n });\n });\n\n it(\"detects TransferChecked without existing ATA \u21D2 createATA\", async () => {\n // given\n const mint = Keypair.generate().publicKey;\n const auth = Keypair.generate().publicKey;\n const ata = Keypair.generate().publicKey;\n const other = Keypair.generate().publicKey;\n getAssociatedTokenAddress.mockResolvedValue(ata);\n\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [1, 2, 3, 4],\n data: new Uint8Array([3]),\n },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, auth, other, other, mint],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction.mockReturnValue({\n data: { mint, authority: auth, source: other, destination: other },\n });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.SPL,\n data: {\n createATA: {\n address: ata.toBase58(),\n mintAddress: mint.toBase58(),\n },\n },\n });\n });\n\n it(\"extractMessage: throws combined error if all three deserializers fail\", () => {\n // given\n vi.spyOn(VersionedTransaction, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vtx fail\");\n });\n vi.spyOn(VersionedMessage, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vmd fail\");\n });\n vi.spyOn(Transaction, \"from\").mockImplementation(() => {\n throw new Error(\"tx fail\");\n });\n\n // when\n const inspector = new TransactionInspector(new Uint8Array([0x01, 0x02]));\n\n // then\n expect(() =>\n (inspector as any).extractMessage(new Uint8Array([0x01, 0x02])),\n ).toThrow(\n /Invalid transaction payload[\\s\\S]*1\\) vtx fail[\\s\\S]*2\\) vmd fail[\\s\\S]*3\\) tx fail/,\n );\n });\n\n it(\"returns STANDARD fallback when all deserialisers throw\", async () => {\n vi.spyOn(VersionedTransaction, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vtx fail\");\n });\n vi.spyOn(VersionedMessage, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vmd fail\");\n });\n vi.spyOn(Transaction, \"from\").mockImplementation(() => {\n throw new Error(\"tx fail\");\n });\n\n const inspector = new TransactionInspector(\n new Uint8Array([0xde, 0xad, 0xbe, 0xef]),\n );\n const result = await inspector.inspectTransactionType();\n\n expect(result).toEqual({\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n });\n });\n});\n\ndescribe(\"isTransferCheckedData\", () => {\n const inspector = new TransactionInspector(new Uint8Array());\n\n it(\"returns false for null or primitive values\", () => {\n expect((inspector as any).isTransferCheckedData(null)).toBe(false);\n expect((inspector as any).isTransferCheckedData(42)).toBe(false);\n expect((inspector as any).isTransferCheckedData(\"string\")).toBe(false);\n });\n\n it(\"returns false for objects missing required keys or wrong types\", () => {\n // given\n const fakePk = Keypair.generate().publicKey;\n\n // when / then\n // Missing keys\n expect(\n (inspector as any).isTransferCheckedData({\n mint: fakePk,\n authority: fakePk,\n }),\n ).toBe(false);\n // Wrong types\n expect(\n (inspector as any).isTransferCheckedData({\n mint: \"nope\",\n authority: null,\n source: {},\n destination: [],\n }),\n ).toBe(false);\n });\n\n it(\"returns true for a properly shaped object\", () => {\n // given\n const fakePk = Keypair.generate().publicKey;\n const data = {\n mint: fakePk,\n authority: fakePk,\n source: fakePk,\n destination: fakePk,\n };\n\n // when / then\n expect((inspector as any).isTransferCheckedData(data)).toBe(true);\n });\n});\n\ndescribe(\"extractMessage legacy fallback\", () => {\n it(\"handles a legacy Transaction via serializeMessage and returns STANDARD\", async () => {\n // given\n vi.spyOn(VersionedTransaction, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vtx fail\");\n });\n vi.spyOn(VersionedMessage, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vmd fail\");\n });\n\n const from = Keypair.generate();\n const to = Keypair.generate();\n const tx = new Transaction().add(\n SystemProgram.transfer({\n fromPubkey: from.publicKey,\n toPubkey: to.publicKey,\n lamports: 1,\n }),\n );\n tx.feePayer = from.publicKey;\n tx.recentBlockhash = \"11111111111111111111111111111111\";\n\n tx.sign(from);\n\n const raw = tx.serialize();\n\n // when\n const result = await new TransactionInspector(raw).inspectTransactionType();\n\n // then\n expect(result.transactionType).toBe(\"Standard\");\n expect(result.data).toEqual({});\n });\n});\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["import {\n createInitializeAccountInstruction,\n createTransferCheckedInstruction,\n createTransferInstruction,\n TOKEN_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport { Keypair, SystemProgram, Transaction } from \"@solana/web3.js\";\nimport bs58 from \"bs58\";\nimport { describe, expect, it } from \"vitest\";\n\nimport {\n SolanaTransactionTypes,\n TransactionInspector,\n} from \"./TransactionInspector\";\n\nconst DUMMY_BLOCKHASH = bs58.encode(new Uint8Array(32).fill(1));\n\ndescribe(\"TransactionInspector\", () => {\n it(\"falls back to STANDARD for a plain SystemProgram transfer\", () => {\n const payer = Keypair.generate();\n const dest = Keypair.generate().publicKey;\n\n const tx = new Transaction().add(\n SystemProgram.transfer({\n fromPubkey: payer.publicKey,\n toPubkey: dest,\n lamports: 1_000,\n }),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const raw = tx.serialize();\n const result = new TransactionInspector(raw).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.STANDARD);\n expect(result.data).toEqual({});\n });\n\n it(\"detects an SPL Transfer and returns the destination address\", () => {\n const payer = Keypair.generate();\n const source = Keypair.generate().publicKey;\n const destination = Keypair.generate().publicKey;\n const owner = payer.publicKey;\n\n const tx = new Transaction().add(\n createTransferInstruction(\n source,\n destination,\n owner,\n 42n,\n [],\n TOKEN_PROGRAM_ID,\n ),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const result = new TransactionInspector(\n tx.serialize(),\n ).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.SPL);\n expect(result.data.tokenAddress).toBe(destination.toBase58());\n });\n\n it(\"detects an SPL TransferChecked and returns the destination address\", () => {\n const payer = Keypair.generate();\n const mint = Keypair.generate().publicKey;\n const source = Keypair.generate().publicKey;\n const destination = Keypair.generate().publicKey;\n const owner = payer.publicKey;\n\n const tx = new Transaction().add(\n createTransferCheckedInstruction(\n source,\n mint,\n destination,\n owner,\n 123n,\n 0,\n [],\n TOKEN_PROGRAM_ID,\n ),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const result = new TransactionInspector(\n tx.serialize(),\n ).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.SPL);\n expect(result.data.tokenAddress).toBe(destination.toBase58());\n });\n\n it(\"detects an SPL InitializeAccount and returns the new ATA and mint\", () => {\n const payer = Keypair.generate();\n const mint = Keypair.generate().publicKey;\n const newAccount = Keypair.generate().publicKey;\n const owner = payer.publicKey;\n\n const tx = new Transaction().add(\n createInitializeAccountInstruction(\n newAccount,\n mint,\n owner,\n TOKEN_PROGRAM_ID,\n ),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const result = new TransactionInspector(\n tx.serialize(),\n ).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.SPL);\n expect(result.data.createATA).toEqual({\n address: newAccount.toBase58(),\n mintAddress: mint.toBase58(),\n });\n });\n\n it(\"falls back to STANDARD if the payload is unparseable\", () => {\n const garbage = new Uint8Array([0, 1, 2, 3, 4, 5]);\n const result = new TransactionInspector(garbage).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.STANDARD);\n expect(result.data).toEqual({});\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_spl_token", "import_web3", "import_bs58", "import_vitest", "import_TransactionInspector", "DUMMY_BLOCKHASH", "bs58", "payer", "dest", "tx", "raw", "result", "source", "destination", "owner", "mint", "newAccount", "garbage"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`+n.map((
|
|
3
|
-
`))}}export{
|
|
1
|
+
import{decodeInitializeAccountInstruction as u,decodeTransferCheckedInstruction as d,decodeTransferInstruction as p,TOKEN_PROGRAM_ID as y,TokenInstruction as c}from"@solana/spl-token";import{Transaction as l,TransactionInstruction as m,VersionedMessage as T,VersionedTransaction as A}from"@solana/web3.js";import{Buffer as I}from"buffer";var f=(n=>(n.STANDARD="Standard",n.SPL="SPL",n))(f||{});class x{constructor(s){this.rawTransactionBytes=s}inspectTransactionType(){try{const s=this.extractMessage(this.rawTransactionBytes);for(const n of s.compiledInstructions){const t=s.staticAccountKeys[n.programIdIndex];if(!t.equals(y))continue;const r=new m({programId:t,keys:n.accountKeyIndexes.map(e=>({pubkey:s.staticAccountKeys[e],isSigner:s.isAccountSigner(e),isWritable:s.isAccountWritable(e)})),data:I.from(n.data)});switch(r.data[0]){case c.Transfer:{const{keys:{destination:e}}=p(r);return{transactionType:"SPL",data:{tokenAddress:e.pubkey.toBase58()}}}case c.TransferChecked:{const{keys:{destination:e}}=d(r);return{transactionType:"SPL",data:{tokenAddress:e.pubkey.toBase58()}}}case c.InitializeAccount:{const{keys:{account:e,mint:a}}=u(r);return{transactionType:"SPL",data:{createATA:{address:e.pubkey.toBase58(),mintAddress:a.pubkey.toBase58()}}}}default:continue}}return{transactionType:"Standard",data:{}}}catch{return{transactionType:"Standard",data:{}}}}extractMessage(s){const n=[];try{return A.deserialize(s).message}catch(t){n.push(t.message)}try{return T.deserialize(s)}catch(t){n.push(t.message)}try{const t=l.from(s),r=[t.feePayer,...t.instructions.flatMap(e=>e.keys.map(a=>a.pubkey))],o=Array.from(new Map(r.filter(Boolean).map(e=>[e.toBase58(),e])).values());return{compiledInstructions:t.instructions.map(e=>({programIdIndex:o.findIndex(a=>a.equals(e.programId)),accountKeyIndexes:e.keys.map(a=>o.findIndex(i=>i.equals(a.pubkey))),data:e.data})),staticAccountKeys:o,isAccountSigner:e=>t.signatures.some(a=>a.publicKey.equals(o[e])),isAccountWritable:()=>!0}}catch(t){n.push(t.message)}throw new Error(`Invalid transaction payload \u2013 all deserializers failed:
|
|
2
|
+
`+n.map((t,r)=>`${r+1}) ${t}`).join(`
|
|
3
|
+
`))}}export{f as SolanaTransactionTypes,x as TransactionInspector};
|
|
4
4
|
//# sourceMappingURL=TransactionInspector.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/services/TransactionInspector.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n
|
|
5
|
-
"mappings": "AAAA,OACE,
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["import {\n decodeInitializeAccountInstruction,\n decodeTransferCheckedInstruction,\n decodeTransferInstruction,\n TOKEN_PROGRAM_ID,\n TokenInstruction,\n} from \"@solana/spl-token\";\nimport {\n type PublicKey,\n Transaction,\n TransactionInstruction,\n VersionedMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { Buffer } from \"buffer\";\n\nexport enum SolanaTransactionTypes {\n STANDARD = \"Standard\",\n SPL = \"SPL\",\n}\nexport interface TxInspectorResult {\n transactionType: SolanaTransactionTypes;\n data: {\n tokenAddress?: string;\n createATA?: {\n address: string;\n mintAddress: string;\n };\n };\n}\n\nexport class TransactionInspector {\n constructor(private readonly rawTransactionBytes: Uint8Array) {}\n\n public inspectTransactionType(): TxInspectorResult {\n try {\n const message = this.extractMessage(this.rawTransactionBytes);\n\n for (const ixMeta of message.compiledInstructions) {\n const programId = message.staticAccountKeys[ixMeta.programIdIndex]!;\n if (!programId.equals(TOKEN_PROGRAM_ID)) continue;\n\n const instruction = new TransactionInstruction({\n programId,\n keys: ixMeta.accountKeyIndexes.map((i) => ({\n pubkey: message.staticAccountKeys[i]!,\n isSigner: message.isAccountSigner(i),\n isWritable: message.isAccountWritable(i),\n })),\n data: Buffer.from(ixMeta.data),\n });\n\n const instructionType = instruction.data[0];\n switch (instructionType) {\n case TokenInstruction.Transfer: {\n const {\n keys: { destination },\n } = decodeTransferInstruction(instruction);\n return {\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: destination.pubkey.toBase58() },\n };\n }\n case TokenInstruction.TransferChecked: {\n const {\n keys: { destination },\n } = decodeTransferCheckedInstruction(instruction);\n return {\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: destination.pubkey.toBase58() },\n };\n }\n case TokenInstruction.InitializeAccount: {\n const {\n keys: { account, mint },\n } = decodeInitializeAccountInstruction(instruction);\n return {\n transactionType: SolanaTransactionTypes.SPL,\n data: {\n createATA: {\n address: account.pubkey.toBase58(),\n mintAddress: mint.pubkey.toBase58(),\n },\n },\n };\n }\n default:\n continue;\n }\n }\n\n return {\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n };\n } catch {\n return {\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n };\n }\n }\n\n private extractMessage(rawBytes: Uint8Array): VersionedMessage {\n const errors: string[] = [];\n try {\n return VersionedTransaction.deserialize(rawBytes).message;\n } catch (e) {\n errors.push((e as Error).message);\n }\n\n try {\n return VersionedMessage.deserialize(rawBytes);\n } catch (e) {\n errors.push((e as Error).message);\n }\n\n try {\n const tx = Transaction.from(rawBytes);\n const allKeys = [\n tx.feePayer,\n ...tx.instructions.flatMap((ix) => ix.keys.map((k) => k.pubkey)),\n ];\n\n const staticAccountKeys = Array.from(\n new Map(\n (allKeys.filter(Boolean) as PublicKey[]).map((pk) => [\n pk.toBase58(),\n pk,\n ]),\n ).values(),\n );\n\n interface CustomCompiledInstruction {\n programIdIndex: number;\n accountKeyIndexes: number[];\n data: Uint8Array;\n }\n\n return {\n compiledInstructions: tx.instructions.map(\n (ix): CustomCompiledInstruction => ({\n programIdIndex: staticAccountKeys.findIndex((k) =>\n k.equals(ix.programId),\n ),\n accountKeyIndexes: ix.keys.map((k) =>\n staticAccountKeys.findIndex((s) => s.equals(k.pubkey)),\n ),\n data: ix.data,\n }),\n ),\n staticAccountKeys,\n isAccountSigner: (i: number) =>\n tx.signatures.some((sig) =>\n sig.publicKey.equals(staticAccountKeys[i]!),\n ),\n isAccountWritable: () => true,\n } as unknown as VersionedMessage;\n } catch (e) {\n errors.push((e as Error).message);\n }\n\n throw new Error(\n \"Invalid transaction payload \u2013 all deserializers failed:\\n\" +\n errors.map((m, i) => `${i + 1}) ${m}`).join(\"\\n\"),\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OACE,sCAAAA,EACA,oCAAAC,EACA,6BAAAC,EACA,oBAAAC,EACA,oBAAAC,MACK,oBACP,OAEE,eAAAC,EACA,0BAAAC,EACA,oBAAAC,EACA,wBAAAC,MACK,kBACP,OAAS,UAAAC,MAAc,SAEhB,IAAKC,OACVA,EAAA,SAAW,WACXA,EAAA,IAAM,MAFIA,OAAA,IAeL,MAAMC,CAAqB,CAChC,YAA6BC,EAAiC,CAAjC,yBAAAA,CAAkC,CAExD,wBAA4C,CACjD,GAAI,CACF,MAAMC,EAAU,KAAK,eAAe,KAAK,mBAAmB,EAE5D,UAAWC,KAAUD,EAAQ,qBAAsB,CACjD,MAAME,EAAYF,EAAQ,kBAAkBC,EAAO,cAAc,EACjE,GAAI,CAACC,EAAU,OAAOZ,CAAgB,EAAG,SAEzC,MAAMa,EAAc,IAAIV,EAAuB,CAC7C,UAAAS,EACA,KAAMD,EAAO,kBAAkB,IAAKG,IAAO,CACzC,OAAQJ,EAAQ,kBAAkBI,CAAC,EACnC,SAAUJ,EAAQ,gBAAgBI,CAAC,EACnC,WAAYJ,EAAQ,kBAAkBI,CAAC,CACzC,EAAE,EACF,KAAMR,EAAO,KAAKK,EAAO,IAAI,CAC/B,CAAC,EAGD,OADwBE,EAAY,KAAK,CAAC,EACjB,CACvB,KAAKZ,EAAiB,SAAU,CAC9B,KAAM,CACJ,KAAM,CAAE,YAAAc,CAAY,CACtB,EAAIhB,EAA0Bc,CAAW,EACzC,MAAO,CACL,gBAAiB,MACjB,KAAM,CAAE,aAAcE,EAAY,OAAO,SAAS,CAAE,CACtD,CACF,CACA,KAAKd,EAAiB,gBAAiB,CACrC,KAAM,CACJ,KAAM,CAAE,YAAAc,CAAY,CACtB,EAAIjB,EAAiCe,CAAW,EAChD,MAAO,CACL,gBAAiB,MACjB,KAAM,CAAE,aAAcE,EAAY,OAAO,SAAS,CAAE,CACtD,CACF,CACA,KAAKd,EAAiB,kBAAmB,CACvC,KAAM,CACJ,KAAM,CAAE,QAAAe,EAAS,KAAAC,CAAK,CACxB,EAAIpB,EAAmCgB,CAAW,EAClD,MAAO,CACL,gBAAiB,MACjB,KAAM,CACJ,UAAW,CACT,QAASG,EAAQ,OAAO,SAAS,EACjC,YAAaC,EAAK,OAAO,SAAS,CACpC,CACF,CACF,CACF,CACA,QACE,QACJ,CACF,CAEA,MAAO,CACL,gBAAiB,WACjB,KAAM,CAAC,CACT,CACF,MAAQ,CACN,MAAO,CACL,gBAAiB,WACjB,KAAM,CAAC,CACT,CACF,CACF,CAEQ,eAAeC,EAAwC,CAC7D,MAAMC,EAAmB,CAAC,EAC1B,GAAI,CACF,OAAOd,EAAqB,YAAYa,CAAQ,EAAE,OACpD,OAASE,EAAG,CACVD,EAAO,KAAMC,EAAY,OAAO,CAClC,CAEA,GAAI,CACF,OAAOhB,EAAiB,YAAYc,CAAQ,CAC9C,OAASE,EAAG,CACVD,EAAO,KAAMC,EAAY,OAAO,CAClC,CAEA,GAAI,CACF,MAAMC,EAAKnB,EAAY,KAAKgB,CAAQ,EAC9BI,EAAU,CACdD,EAAG,SACH,GAAGA,EAAG,aAAa,QAASE,GAAOA,EAAG,KAAK,IAAKC,GAAMA,EAAE,MAAM,CAAC,CACjE,EAEMC,EAAoB,MAAM,KAC9B,IAAI,IACDH,EAAQ,OAAO,OAAO,EAAkB,IAAKI,GAAO,CACnDA,EAAG,SAAS,EACZA,CACF,CAAC,CACH,EAAE,OAAO,CACX,EAQA,MAAO,CACL,qBAAsBL,EAAG,aAAa,IACnCE,IAAmC,CAClC,eAAgBE,EAAkB,UAAWD,GAC3CA,EAAE,OAAOD,EAAG,SAAS,CACvB,EACA,kBAAmBA,EAAG,KAAK,IAAKC,GAC9BC,EAAkB,UAAWE,GAAMA,EAAE,OAAOH,EAAE,MAAM,CAAC,CACvD,EACA,KAAMD,EAAG,IACX,EACF,EACA,kBAAAE,EACA,gBAAkBX,GAChBO,EAAG,WAAW,KAAMO,GAClBA,EAAI,UAAU,OAAOH,EAAkBX,CAAC,CAAE,CAC5C,EACF,kBAAmB,IAAM,EAC3B,CACF,OAASM,EAAG,CACVD,EAAO,KAAMC,EAAY,OAAO,CAClC,CAEA,MAAM,IAAI,MACR;AAAA,EACED,EAAO,IAAI,CAACU,EAAGf,IAAM,GAAGA,EAAI,CAAC,KAAKe,CAAC,EAAE,EAAE,KAAK;AAAA,CAAI,CACpD,CACF,CACF",
|
|
6
|
+
"names": ["decodeInitializeAccountInstruction", "decodeTransferCheckedInstruction", "decodeTransferInstruction", "TOKEN_PROGRAM_ID", "TokenInstruction", "Transaction", "TransactionInstruction", "VersionedMessage", "VersionedTransaction", "Buffer", "SolanaTransactionTypes", "TransactionInspector", "rawTransactionBytes", "message", "ixMeta", "programId", "instruction", "i", "destination", "account", "mint", "rawBytes", "errors", "e", "tx", "allKeys", "ix", "k", "staticAccountKeys", "pk", "s", "sig", "m"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import{createInitializeAccountInstruction as b,createTransferCheckedInstruction as A,createTransferInstruction as f,TOKEN_PROGRAM_ID as u}from"@solana/spl-token";import{Keypair as a,SystemProgram as g,Transaction as y}from"@solana/web3.js";import m from"bs58";import{describe as K,expect as o,it as i}from"vitest";import{SolanaTransactionTypes as p,TransactionInspector as l}from"./TransactionInspector";const d=m.encode(new Uint8Array(32).fill(1));K("TransactionInspector",()=>{i("falls back to STANDARD for a plain SystemProgram transfer",()=>{const e=a.generate(),s=a.generate().publicKey,n=new y().add(g.transfer({fromPubkey:e.publicKey,toPubkey:s,lamports:1e3}));n.recentBlockhash=d,n.feePayer=e.publicKey,n.sign(e);const c=n.serialize(),t=new l(c).inspectTransactionType();o(t.transactionType).toBe(p.STANDARD),o(t.data).toEqual({})}),i("detects an SPL Transfer and returns the destination address",()=>{const e=a.generate(),s=a.generate().publicKey,n=a.generate().publicKey,c=e.publicKey,t=new y().add(f(s,n,c,42n,[],u));t.recentBlockhash=d,t.feePayer=e.publicKey,t.sign(e);const r=new l(t.serialize()).inspectTransactionType();o(r.transactionType).toBe(p.SPL),o(r.data.tokenAddress).toBe(n.toBase58())}),i("detects an SPL TransferChecked and returns the destination address",()=>{const e=a.generate(),s=a.generate().publicKey,n=a.generate().publicKey,c=a.generate().publicKey,t=e.publicKey,r=new y().add(A(n,s,c,t,123n,0,[],u));r.recentBlockhash=d,r.feePayer=e.publicKey,r.sign(e);const T=new l(r.serialize()).inspectTransactionType();o(T.transactionType).toBe(p.SPL),o(T.data.tokenAddress).toBe(c.toBase58())}),i("detects an SPL InitializeAccount and returns the new ATA and mint",()=>{const e=a.generate(),s=a.generate().publicKey,n=a.generate().publicKey,c=e.publicKey,t=new y().add(b(n,s,c,u));t.recentBlockhash=d,t.feePayer=e.publicKey,t.sign(e);const r=new l(t.serialize()).inspectTransactionType();o(r.transactionType).toBe(p.SPL),o(r.data.createATA).toEqual({address:n.toBase58(),mintAddress:s.toBase58()})}),i("falls back to STANDARD if the payload is unparseable",()=>{const e=new Uint8Array([0,1,2,3,4,5]),s=new l(e).inspectTransactionType();o(s.transactionType).toBe(p.STANDARD),o(s.data).toEqual({})})});
|
|
2
2
|
//# sourceMappingURL=TransactionInspector.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/internal/app-binder/services/TransactionInspector.test.ts"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as splToken from \"@solana/spl-token\";\nimport {\n Keypair,\n type PublicKey,\n SystemProgram,\n Transaction,\n type TransactionInstruction,\n VersionedMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\n\nimport {\n SolanaTransactionTypes,\n TransactionInspector,\n} from \"./TransactionInspector\";\n\nfunction makeFakeMessage(opts: {\n compiledInstructions: Array<{\n programIdIndex: number;\n accountKeyIndexes: number[];\n data: Uint8Array | number[] | Buffer;\n }>;\n staticAccountKeys: PublicKey[];\n}): VersionedMessage {\n return {\n compiledInstructions: opts.compiledInstructions.map((ix) => ({\n ...ix,\n data:\n ix.data instanceof Uint8Array\n ? ix.data\n : typeof Buffer !== \"undefined\" && ix.data instanceof Buffer\n ? ix.data\n : new Uint8Array(ix.data as number[]),\n })),\n staticAccountKeys: opts.staticAccountKeys,\n isAccountSigner: (_: number) => false,\n isAccountWritable: (_: number) => false,\n } as any;\n}\n\nvi.mock(\"@solana/spl-token\", async () => {\n const actual = await vi.importActual<any>(\"@solana/spl-token\");\n return {\n ...actual,\n decodeInstruction: vi.fn(),\n getAssociatedTokenAddress: vi.fn(),\n TOKEN_PROGRAM_ID: actual.TOKEN_PROGRAM_ID,\n };\n});\nconst { decodeInstruction, getAssociatedTokenAddress, TOKEN_PROGRAM_ID } =\n splToken as any;\n\ndescribe(\"TransactionInspector\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n it(\"returns STANDARD when no SPL instructions are found\", async () => {\n // given\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(\n makeFakeMessage({ compiledInstructions: [], staticAccountKeys: [] }),\n );\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n });\n });\n\n it(\"ignores instructions not targeting TOKEN_PROGRAM_ID\", async () => {\n // given\n const fakePk = Keypair.generate().publicKey;\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [1],\n data: new Uint8Array([1]),\n },\n ],\n staticAccountKeys: [fakePk, Keypair.generate().publicKey],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res.transactionType).toBe(SolanaTransactionTypes.STANDARD);\n });\n\n it(\"skips a first bad decodeInstruction and succeeds on the next\", async () => {\n // given\n const dest = Keypair.generate().publicKey;\n const other = Keypair.generate().publicKey;\n\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [0, 1, 2],\n data: new Uint8Array([0]),\n },\n {\n programIdIndex: 0,\n accountKeyIndexes: [0, 1, 2],\n data: new Uint8Array([0]),\n },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, other, dest],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction\n .mockReturnValueOnce(new Error(\"bad\"))\n .mockReturnValueOnce({ data: { amount: 7 } });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: dest.toBase58() },\n });\n });\n\n it(\"converts Buffer or number[] data into Uint8Array before decoding\", async () => {\n // given\n const dest = Keypair.generate().publicKey;\n const other = Keypair.generate().publicKey;\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [0, 1, 2],\n data: Buffer.from([5, 6, 7]),\n },\n { programIdIndex: 0, accountKeyIndexes: [0, 1, 2], data: [8, 9, 10] },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, other, dest],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction\n .mockReturnValueOnce(new Error(\"nope\"))\n .mockImplementation((ix: TransactionInstruction) => {\n expect(ix.data).toBeInstanceOf(Uint8Array);\n return { data: { amount: 21 } };\n });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res.data).toEqual({ tokenAddress: dest.toBase58() });\n });\n\n it(\"detects TransferChecked with existing ATA\", async () => {\n // given\n const mint = Keypair.generate().publicKey;\n const auth = Keypair.generate().publicKey;\n const ata = Keypair.generate().publicKey;\n getAssociatedTokenAddress.mockResolvedValue(ata);\n\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [1, 2, 3, 4],\n data: new Uint8Array([3]),\n },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, auth, ata, ata, mint],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction.mockReturnValue({\n data: { mint, authority: auth, source: ata, destination: ata },\n });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.SPL,\n data: { tokenAddress: ata.toBase58() },\n });\n });\n\n it(\"detects TransferChecked without existing ATA \u21D2 createATA\", async () => {\n // given\n const mint = Keypair.generate().publicKey;\n const auth = Keypair.generate().publicKey;\n const ata = Keypair.generate().publicKey;\n const other = Keypair.generate().publicKey;\n getAssociatedTokenAddress.mockResolvedValue(ata);\n\n const msg = makeFakeMessage({\n compiledInstructions: [\n {\n programIdIndex: 0,\n accountKeyIndexes: [1, 2, 3, 4],\n data: new Uint8Array([3]),\n },\n ],\n staticAccountKeys: [TOKEN_PROGRAM_ID, auth, other, other, mint],\n });\n const inspector = new TransactionInspector(new Uint8Array());\n vi.spyOn(inspector as any, \"extractMessage\").mockReturnValue(msg);\n\n decodeInstruction.mockReturnValue({\n data: { mint, authority: auth, source: other, destination: other },\n });\n\n // when\n const res = await inspector.inspectTransactionType();\n\n // then\n expect(res).toEqual({\n transactionType: SolanaTransactionTypes.SPL,\n data: {\n createATA: {\n address: ata.toBase58(),\n mintAddress: mint.toBase58(),\n },\n },\n });\n });\n\n it(\"extractMessage: throws combined error if all three deserializers fail\", () => {\n // given\n vi.spyOn(VersionedTransaction, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vtx fail\");\n });\n vi.spyOn(VersionedMessage, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vmd fail\");\n });\n vi.spyOn(Transaction, \"from\").mockImplementation(() => {\n throw new Error(\"tx fail\");\n });\n\n // when\n const inspector = new TransactionInspector(new Uint8Array([0x01, 0x02]));\n\n // then\n expect(() =>\n (inspector as any).extractMessage(new Uint8Array([0x01, 0x02])),\n ).toThrow(\n /Invalid transaction payload[\\s\\S]*1\\) vtx fail[\\s\\S]*2\\) vmd fail[\\s\\S]*3\\) tx fail/,\n );\n });\n\n it(\"returns STANDARD fallback when all deserialisers throw\", async () => {\n vi.spyOn(VersionedTransaction, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vtx fail\");\n });\n vi.spyOn(VersionedMessage, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vmd fail\");\n });\n vi.spyOn(Transaction, \"from\").mockImplementation(() => {\n throw new Error(\"tx fail\");\n });\n\n const inspector = new TransactionInspector(\n new Uint8Array([0xde, 0xad, 0xbe, 0xef]),\n );\n const result = await inspector.inspectTransactionType();\n\n expect(result).toEqual({\n transactionType: SolanaTransactionTypes.STANDARD,\n data: {},\n });\n });\n});\n\ndescribe(\"isTransferCheckedData\", () => {\n const inspector = new TransactionInspector(new Uint8Array());\n\n it(\"returns false for null or primitive values\", () => {\n expect((inspector as any).isTransferCheckedData(null)).toBe(false);\n expect((inspector as any).isTransferCheckedData(42)).toBe(false);\n expect((inspector as any).isTransferCheckedData(\"string\")).toBe(false);\n });\n\n it(\"returns false for objects missing required keys or wrong types\", () => {\n // given\n const fakePk = Keypair.generate().publicKey;\n\n // when / then\n // Missing keys\n expect(\n (inspector as any).isTransferCheckedData({\n mint: fakePk,\n authority: fakePk,\n }),\n ).toBe(false);\n // Wrong types\n expect(\n (inspector as any).isTransferCheckedData({\n mint: \"nope\",\n authority: null,\n source: {},\n destination: [],\n }),\n ).toBe(false);\n });\n\n it(\"returns true for a properly shaped object\", () => {\n // given\n const fakePk = Keypair.generate().publicKey;\n const data = {\n mint: fakePk,\n authority: fakePk,\n source: fakePk,\n destination: fakePk,\n };\n\n // when / then\n expect((inspector as any).isTransferCheckedData(data)).toBe(true);\n });\n});\n\ndescribe(\"extractMessage legacy fallback\", () => {\n it(\"handles a legacy Transaction via serializeMessage and returns STANDARD\", async () => {\n // given\n vi.spyOn(VersionedTransaction, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vtx fail\");\n });\n vi.spyOn(VersionedMessage, \"deserialize\").mockImplementation(() => {\n throw new Error(\"vmd fail\");\n });\n\n const from = Keypair.generate();\n const to = Keypair.generate();\n const tx = new Transaction().add(\n SystemProgram.transfer({\n fromPubkey: from.publicKey,\n toPubkey: to.publicKey,\n lamports: 1,\n }),\n );\n tx.feePayer = from.publicKey;\n tx.recentBlockhash = \"11111111111111111111111111111111\";\n\n tx.sign(from);\n\n const raw = tx.serialize();\n\n // when\n const result = await new TransactionInspector(raw).inspectTransactionType();\n\n // then\n expect(result.transactionType).toBe(\"Standard\");\n expect(result.data).toEqual({});\n });\n});\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["import {\n createInitializeAccountInstruction,\n createTransferCheckedInstruction,\n createTransferInstruction,\n TOKEN_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport { Keypair, SystemProgram, Transaction } from \"@solana/web3.js\";\nimport bs58 from \"bs58\";\nimport { describe, expect, it } from \"vitest\";\n\nimport {\n SolanaTransactionTypes,\n TransactionInspector,\n} from \"./TransactionInspector\";\n\nconst DUMMY_BLOCKHASH = bs58.encode(new Uint8Array(32).fill(1));\n\ndescribe(\"TransactionInspector\", () => {\n it(\"falls back to STANDARD for a plain SystemProgram transfer\", () => {\n const payer = Keypair.generate();\n const dest = Keypair.generate().publicKey;\n\n const tx = new Transaction().add(\n SystemProgram.transfer({\n fromPubkey: payer.publicKey,\n toPubkey: dest,\n lamports: 1_000,\n }),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const raw = tx.serialize();\n const result = new TransactionInspector(raw).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.STANDARD);\n expect(result.data).toEqual({});\n });\n\n it(\"detects an SPL Transfer and returns the destination address\", () => {\n const payer = Keypair.generate();\n const source = Keypair.generate().publicKey;\n const destination = Keypair.generate().publicKey;\n const owner = payer.publicKey;\n\n const tx = new Transaction().add(\n createTransferInstruction(\n source,\n destination,\n owner,\n 42n,\n [],\n TOKEN_PROGRAM_ID,\n ),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const result = new TransactionInspector(\n tx.serialize(),\n ).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.SPL);\n expect(result.data.tokenAddress).toBe(destination.toBase58());\n });\n\n it(\"detects an SPL TransferChecked and returns the destination address\", () => {\n const payer = Keypair.generate();\n const mint = Keypair.generate().publicKey;\n const source = Keypair.generate().publicKey;\n const destination = Keypair.generate().publicKey;\n const owner = payer.publicKey;\n\n const tx = new Transaction().add(\n createTransferCheckedInstruction(\n source,\n mint,\n destination,\n owner,\n 123n,\n 0,\n [],\n TOKEN_PROGRAM_ID,\n ),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const result = new TransactionInspector(\n tx.serialize(),\n ).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.SPL);\n expect(result.data.tokenAddress).toBe(destination.toBase58());\n });\n\n it(\"detects an SPL InitializeAccount and returns the new ATA and mint\", () => {\n const payer = Keypair.generate();\n const mint = Keypair.generate().publicKey;\n const newAccount = Keypair.generate().publicKey;\n const owner = payer.publicKey;\n\n const tx = new Transaction().add(\n createInitializeAccountInstruction(\n newAccount,\n mint,\n owner,\n TOKEN_PROGRAM_ID,\n ),\n );\n tx.recentBlockhash = DUMMY_BLOCKHASH;\n tx.feePayer = payer.publicKey;\n tx.sign(payer);\n\n const result = new TransactionInspector(\n tx.serialize(),\n ).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.SPL);\n expect(result.data.createATA).toEqual({\n address: newAccount.toBase58(),\n mintAddress: mint.toBase58(),\n });\n });\n\n it(\"falls back to STANDARD if the payload is unparseable\", () => {\n const garbage = new Uint8Array([0, 1, 2, 3, 4, 5]);\n const result = new TransactionInspector(garbage).inspectTransactionType();\n\n expect(result.transactionType).toBe(SolanaTransactionTypes.STANDARD);\n expect(result.data).toEqual({});\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["createInitializeAccountInstruction", "createTransferCheckedInstruction", "createTransferInstruction", "TOKEN_PROGRAM_ID", "Keypair", "SystemProgram", "Transaction", "bs58", "describe", "expect", "it", "SolanaTransactionTypes", "TransactionInspector", "DUMMY_BLOCKHASH", "payer", "dest", "tx", "raw", "result", "source", "destination", "owner", "mint", "newAccount", "garbage"]
|
|
7
7
|
}
|
|
@@ -15,8 +15,7 @@ export interface TxInspectorResult {
|
|
|
15
15
|
export declare class TransactionInspector {
|
|
16
16
|
private readonly rawTransactionBytes;
|
|
17
17
|
constructor(rawTransactionBytes: Uint8Array);
|
|
18
|
-
inspectTransactionType():
|
|
19
|
-
private isTransferCheckedData;
|
|
18
|
+
inspectTransactionType(): TxInspectorResult;
|
|
20
19
|
private extractMessage;
|
|
21
20
|
}
|
|
22
21
|
//# sourceMappingURL=TransactionInspector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionInspector.d.ts","sourceRoot":"","sources":["../../../../../src/internal/app-binder/services/TransactionInspector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TransactionInspector.d.ts","sourceRoot":"","sources":["../../../../../src/internal/app-binder/services/TransactionInspector.ts"],"names":[],"mappings":"AAgBA,oBAAY,sBAAsB;IAChC,QAAQ,aAAa;IACrB,GAAG,QAAQ;CACZ;AACD,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,sBAAsB,CAAC;IACxC,IAAI,EAAE;QACJ,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE;YACV,OAAO,EAAE,MAAM,CAAC;YAChB,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC;KACH,CAAC;CACH;AAED,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;gBAAnB,mBAAmB,EAAE,UAAU;IAErD,sBAAsB,IAAI,iBAAiB;IAqElD,OAAO,CAAC,cAAc;CAgEvB"}
|