Skip to content

Commit 80c2429

Browse files
feat: decode standard instructions
1 parent 3e7878f commit 80c2429

17 files changed

Lines changed: 884 additions & 139 deletions

File tree

packages/snap/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@solana-program/compute-budget": "0.7.0",
5353
"@solana-program/system": "0.7.0",
5454
"@solana-program/token": "0.5.1",
55+
"@solana-program/token-2022": "^0.4.2",
5556
"@solana/kit": "2.1.0",
5657
"@testing-library/jest-dom": "^6.6.2",
5758
"@types/express": "^5.0.0",

packages/snap/src/core/serialization/deserialize.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,10 @@ describe('deserialize', () => {
8686
nullValue: null,
8787
});
8888
});
89+
90+
it('deserializes Uint8Array', () => {
91+
const input = { __type: 'Uint8Array', value: 'AQID' };
92+
const result = deserialize(input);
93+
expect(result).toStrictEqual(new Uint8Array([1, 2, 3]));
94+
});
8995
});

packages/snap/src/core/serialization/deserialize.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Json } from '@metamask/snaps-sdk';
2+
import { getBase64Codec } from '@solana/kit';
23
import BigNumber from 'bignumber.js';
34

45
import type { Serializable } from './types';
@@ -28,5 +29,9 @@ export const deserialize = (serializedValue: Json): Serializable =>
2829
return BigInt(value.value);
2930
}
3031

32+
if (value.__type === 'Uint8Array') {
33+
return getBase64Codec().encode(value.value);
34+
}
35+
3136
return value;
3237
});

packages/snap/src/core/serialization/serialize.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,13 @@ describe('serialize', () => {
9595
},
9696
});
9797
});
98+
99+
it('serializes Uint8Array', () => {
100+
const input = new Uint8Array([1, 2, 3]);
101+
const result = serialize(input);
102+
expect(result).toStrictEqual({
103+
__type: 'Uint8Array',
104+
value: 'AQID',
105+
});
106+
});
98107
});

packages/snap/src/core/serialization/serialize.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/naming-convention */
22
import type { Json } from '@metamask/snaps-sdk';
3+
import { getBase64Codec } from '@solana/kit';
34
import BigNumber from 'bignumber.js';
45
import { cloneDeepWith } from 'lodash';
56

@@ -35,6 +36,13 @@ export const serialize = (value: Serializable): Record<string, Json> =>
3536
};
3637
}
3738

39+
if (val instanceof Uint8Array) {
40+
return {
41+
__type: 'Uint8Array',
42+
value: getBase64Codec().decode(val),
43+
};
44+
}
45+
3846
// Return undefined to let lodash handle the cloning of other values
3947
return undefined;
4048
});

packages/snap/src/core/serialization/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type Serializable =
1010
| null
1111
| bigint
1212
| BigNumber
13+
| Uint8Array
1314
| Serializable[]
1415
| {
1516
[prop: string]: Serializable;

packages/snap/src/core/services/execution/TransactionHelper.test.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ describe('TransactionHelper', () => {
199199
transactionMessageBase64Encoded,
200200
getMultipleAccountsResponse,
201201
signedTransaction,
202-
signedTransactionBase64Encoded,
203202
signature,
204203
} = scenario;
205204

@@ -218,28 +217,6 @@ describe('TransactionHelper', () => {
218217
});
219218
});
220219

221-
describe('extractInstructionsFromBase64String', () => {
222-
it(`Scenario ${name}: successfully extracts instructions from a base64 encoded transaction message`, async () => {
223-
const result =
224-
await transactionHelper.extractInstructionsFromUnknownBase64String(
225-
transactionMessageBase64Encoded,
226-
scope,
227-
);
228-
229-
expect(result).not.toHaveLength(0);
230-
});
231-
232-
it(`Scenario ${name}: successfully extracts instructions from a base64 encoded transaction`, async () => {
233-
const result =
234-
await transactionHelper.extractInstructionsFromUnknownBase64String(
235-
signedTransactionBase64Encoded,
236-
scope,
237-
);
238-
239-
expect(result).not.toHaveLength(0);
240-
});
241-
});
242-
243220
describe('partiallySignBase64String', () => {
244221
describe('when the base64 string represents a transaction message', () => {
245222
it(`Scenario ${name}: signs a transaction message successfully`, async () => {

packages/snap/src/core/services/execution/TransactionHelper.ts

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Infer } from '@metamask/superstruct';
22
import { assert } from '@metamask/superstruct';
33
import type {
44
BaseTransactionMessage,
5-
CompilableTransactionMessage,
65
GetTransactionApi,
76
Transaction,
87
TransactionMessageBytesBase64,
@@ -22,7 +21,7 @@ import {
2221
type Blockhash,
2322
} from '@solana/kit';
2423

25-
import type { SolanaKeyringAccount } from '../../../entities';
24+
import { type SolanaKeyringAccount } from '../../../entities';
2625
import type { Network } from '../../constants/solana';
2726
import type { DecompileTransactionMessageFetchingLookupTablesConfig } from '../../sdk-extensions/codecs';
2827
import {
@@ -394,37 +393,4 @@ export class TransactionHelper {
394393

395394
return partiallySignTransaction([keyPair], transaction);
396395
}
397-
398-
/**
399-
* Extracts the instructions from a base64 string, adapting the logic depending on whether
400-
* the string represents a transaction or a transaction message.
401-
*
402-
* @param base64EncodedString - The base64 encoded string to extract the instructions from.
403-
* @param scope - The network on which the transaction is being sent.
404-
* @returns The instructions from the base64 encoded string.
405-
* @throws If the base64 encoded string is not a valid transaction or transaction message.
406-
*/
407-
async extractInstructionsFromUnknownBase64String(
408-
base64EncodedString: Infer<typeof Base64Struct>,
409-
scope: Network,
410-
): Promise<CompilableTransactionMessage['instructions']> {
411-
const rpc = this.#connection.getRpc(scope);
412-
413-
const transactionOrTransactionMessage =
414-
await fromUnknowBase64StringToTransactionOrTransactionMessage(
415-
base64EncodedString,
416-
rpc,
417-
);
418-
419-
if ('instructions' in transactionOrTransactionMessage) {
420-
return transactionOrTransactionMessage.instructions;
421-
}
422-
423-
const transactionMessage = await fromBytesToCompilableTransactionMessage(
424-
transactionOrTransactionMessage.messageBytes,
425-
rpc,
426-
);
427-
428-
return transactionMessage.instructions;
429-
}
430396
}

packages/snap/src/core/utils/instructions.ts

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './instructions';
12
export * from './keyring-account';

0 commit comments

Comments
 (0)