Skip to content

Commit 41531f8

Browse files
feat(sdk-coin-sol): add getInstructionType for closeATA
TICKET: WIN-3627
1 parent ab1ff77 commit 41531f8

File tree

6 files changed

+52
-3
lines changed

6 files changed

+52
-3
lines changed

modules/sdk-coin-sol/src/lib/iface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { TransactionExplanation as BaseTransactionExplanation } from '@bitgo/sdk-core';
2+
import { DecodedCloseAccountInstruction } from '@solana/spl-token';
23
import { Blockhash, StakeInstructionType, SystemInstructionType, TransactionSignature } from '@solana/web3.js';
34
import { InstructionBuilderTypes } from './constants';
45

@@ -120,6 +121,7 @@ export type ValidInstructionTypes =
120121
| 'Memo'
121122
| 'InitializeAssociatedTokenAccount'
122123
| 'CloseAssociatedTokenAccount'
124+
| DecodedCloseAccountInstruction
123125
| 'TokenTransfer';
124126

125127
export type StakingAuthorizeParams = {

modules/sdk-coin-sol/src/lib/instructionParamsFactory.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ function parseWalletInitInstructions(instructions: TransactionInstruction[]): Ar
114114
*/
115115
function parseSendInstructions(
116116
instructions: TransactionInstruction[]
117-
): Array<Nonce | Memo | Transfer | TokenTransfer | AtaInit> {
118-
const instructionData: Array<Nonce | Memo | Transfer | TokenTransfer | AtaInit> = [];
117+
): Array<Nonce | Memo | Transfer | TokenTransfer | AtaInit | AtaClose> {
118+
const instructionData: Array<Nonce | Memo | Transfer | TokenTransfer | AtaInit | AtaClose> = [];
119119
for (const instruction of instructions) {
120120
const type = getInstructionType(instruction);
121121
switch (type) {
@@ -177,6 +177,22 @@ function parseSendInstructions(
177177
};
178178
instructionData.push(ataInit);
179179
break;
180+
case ValidInstructionTypesEnum.CloseAssociatedTokenAccount:
181+
const accountAddress = instruction.keys[closeAtaInstructionKeysIndexes.AccountAddress].pubkey.toString();
182+
const destinationAddress =
183+
instruction.keys[closeAtaInstructionKeysIndexes.DestinationAddress].pubkey.toString();
184+
const authorityAddress = instruction.keys[closeAtaInstructionKeysIndexes.AuthorityAddress].pubkey.toString();
185+
186+
const ataClose: AtaClose = {
187+
type: InstructionBuilderTypes.CloseAssociatedTokenAccount,
188+
params: {
189+
accountAddress,
190+
destinationAddress,
191+
authorityAddress,
192+
},
193+
};
194+
instructionData.push(ataClose);
195+
break;
180196
default:
181197
throw new NotSupported(
182198
'Invalid transaction, instruction type not supported: ' + getInstructionType(instruction)
@@ -572,6 +588,12 @@ const ataInitInstructionKeysIndexes = {
572588
MintAddress: 3,
573589
};
574590

591+
const closeAtaInstructionKeysIndexes = {
592+
AccountAddress: 0,
593+
DestinationAddress: 1,
594+
AuthorityAddress: 2,
595+
};
596+
575597
/**
576598
* Parses Solana instructions to initialize associated token account tx instructions params
577599
*

modules/sdk-coin-sol/src/lib/transactionBuilderFactory.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
5656
return this.getStakingRawMsgAuthorizeBuilder(tx);
5757
case TransactionType.StakingDelegate:
5858
return this.getStakingDelegateBuilder(tx);
59+
case TransactionType.CloseAssociatedTokenAccount:
60+
return this.getCloseAtaInitializationBuilder(tx);
5961
default:
6062
throw new InvalidTransactionError('Invalid transaction');
6163
}

modules/sdk-coin-sol/src/lib/utils.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import {
77
UtilsError,
88
} from '@bitgo/sdk-core';
99
import { BaseCoin, BaseNetwork, CoinNotDefinedError, coins, SolCoin } from '@bitgo/statics';
10-
import { ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from '@solana/spl-token';
10+
import {
11+
ASSOCIATED_TOKEN_PROGRAM_ID,
12+
decodeCloseAccountInstruction,
13+
getAssociatedTokenAddress,
14+
TOKEN_PROGRAM_ID,
15+
} from '@solana/spl-token';
1116
import {
1217
Keypair,
1318
PublicKey,
@@ -317,6 +322,15 @@ export function getInstructionType(instruction: TransactionInstruction): ValidIn
317322
case SystemProgram.programId.toString():
318323
return SystemInstruction.decodeInstructionType(instruction);
319324
case TOKEN_PROGRAM_ID.toString():
325+
try {
326+
const decodedInstruction = decodeCloseAccountInstruction(instruction);
327+
if (decodedInstruction && decodedInstruction.data.instruction === 9) {
328+
return 'CloseAssociatedTokenAccount';
329+
}
330+
} catch (e) {
331+
// ignore error and default to TokenTransfer
332+
return 'TokenTransfer';
333+
}
320334
return 'TokenTransfer';
321335
case StakeProgram.programId.toString():
322336
return StakeInstruction.decodeInstructionType(instruction);

modules/sdk-coin-sol/test/resources/sol.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ export const WALLET_INIT_SIGNED_TX_AMOUNT_ZERO =
242242
export const WALLET_INIT_WITH_MEMO_SIGNED_TX =
243243
'AqGFtzbc6Lm0D13WSbjsbsEN4GmCxFAzaphz8ipBhF7BHIsPqlcv/zu8wTu3ryfB7ny5cnqmGgi88cOfjlSLbQdImqIjSu6UPeh0AwisKTwneKt9gnImE6XurWWb2L2eXNad5kvpel5aYN4rZz6UqnQ9KDnQ7mKgbyEE0Ser7IQHAgAEBkXlebz5JTz2i0ff8fs6OlwsIbrFsjwJrhKm4FVr8ItBb/oSifqcWWi8BxhMpNkr6eT3wAuWRIv8GCNbT0xx4W4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVKU1qZKSEGTSTocWDaOHx8NbXdvJK7geQfqEBBBUSNBqfVFxksVo7gioRfc9KXiM8DXDFFshqzRNgGLqlAAAAGp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAOMy2vkvq+zotj/3pEAF5f39mvoVh1a2HFqV+QSzuNCBAwICAAE0AAAAAOCTBAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIDAQQFJAYAAABF5Xm8+SU89otH3/H7OjpcLCG6xbI8Ca4SpuBVa/CLQQMAF3Rlc3QgbWVtbyBwbGVhc2UgaWdub3Jl';
244244

245+
export const TRANSFER_UNSIGNED_TX_CLOSE_ATA =
246+
'AfuVuP3Jpn7kCNwtns6WFvu9+HP1xN6P3tsDHKAhO2zy62rSlty0dNKxnPx+WyLUDWGmpYPEXabSfE/jlsFmUAABAAEEzHRWFgUbrdfkG3wS6dzsLMQ2hDz0rHnxi0c1qPUJfiOoLoy5b0/J9nNRKigGU3Tgw++V+r1f+t8cl9WwxHcCVsmQxO8jc2e2bJKkHxMQd0EMz5SHLNf4shA7bHPlwLabBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKnMSQ6SjNLjhzuzQ/yV2jMXnKYPTb9GwsNukSmdVdTmuQEDAwECAAEJ'; // from sol sdk recover flow testcase
247+
245248
export const TRANSFER_UNSIGNED_TX_WITH_MEMO =
246249
'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIEReV5vPklPPaLR9/x+zo6XCwhusWyPAmuEqbgVWvwi0GpGBtS9+2Q6usNrUtxvrRTg2FnYTFxfpMJWBBft6OJ1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI3jMtr5L6vs6LY/96RABeX9/Zr6FYdWthxalfkEs7jQgQICAgABDAIAAADgkwQAAAAAAAMACXRlc3QgbWVtbw==';
247250
export const TRANSFER_UNSIGNED_TX_WITHOUT_MEMO =

modules/sdk-coin-sol/test/unit/sol.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,12 @@ describe('SOL:', function () {
13371337
const signingPayload = await basecoin.getSignablePayload(resources.TRANSFER_UNSIGNED_TX_WITH_MEMO);
13381338
signingPayload.should.be.deepEqual(rebuiltSignablePayload);
13391339
});
1340+
1341+
it('should build CloseAssociatedTokenAccount txn builder from raw txn', async function () {
1342+
const factory = getBuilderFactory(basecoin.getChain());
1343+
const txnBuilder = factory.from(resources.TRANSFER_UNSIGNED_TX_CLOSE_ATA);
1344+
assert.ok(txnBuilder);
1345+
});
13401346
});
13411347

13421348
describe('Presign transaction', () => {

0 commit comments

Comments
 (0)