Skip to content

Commit 4f4593b

Browse files
authored
Merge pull request #6272 from BitGo/sol-statics
remove statics dependency from sol module
2 parents a228a93 + 487d098 commit 4f4593b

18 files changed

+546
-61
lines changed

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export class AtaInitializationBuilder extends TransactionBuilder {
4242
this._tokenAssociateRecipients.push({
4343
ownerAddress: ataInitInstruction.params.ownerAddress,
4444
tokenName: ataInitInstruction.params.tokenName,
45+
tokenAddress: ataInitInstruction.params.mintAddress,
46+
programId: ataInitInstruction.params.programId,
4547
});
4648
}
4749
}
@@ -115,10 +117,15 @@ export class AtaInitializationBuilder extends TransactionBuilder {
115117
}
116118
validateOwnerAddress(recipient.ownerAddress);
117119
const token = getSolTokenFromTokenName(recipient.tokenName);
118-
if (!token) {
120+
let tokenAddress: string;
121+
if (recipient.tokenAddress) {
122+
tokenAddress = recipient.tokenAddress;
123+
} else if (token) {
124+
tokenAddress = token.tokenAddress;
125+
} else {
119126
throw new BuildTransactionError('Invalid transaction: invalid token name, got: ' + recipient.tokenName);
120127
}
121-
validateMintAddress(token.tokenAddress);
128+
validateMintAddress(tokenAddress);
122129

123130
this._tokenAssociateRecipients.push(recipient);
124131
return this;
@@ -141,25 +148,33 @@ export class AtaInitializationBuilder extends TransactionBuilder {
141148
await Promise.all(
142149
this._tokenAssociateRecipients.map(async (recipient) => {
143150
const token = getSolTokenFromTokenName(recipient.tokenName);
144-
if (!token) {
151+
let tokenAddress: string;
152+
let programId: string;
153+
if (recipient.tokenAddress && recipient.programId) {
154+
tokenAddress = recipient.tokenAddress;
155+
programId = recipient.programId;
156+
} else if (token) {
157+
tokenAddress = token.tokenAddress;
158+
programId = token.programId;
159+
} else {
145160
throw new BuildTransactionError('Invalid transaction: invalid token name, got: ' + recipient.tokenName);
146161
}
147162

148163
// Use the provided ataAddress if it exists, otherwise calculate it
149164
let ataPk = recipient.ataAddress;
150165
if (!ataPk) {
151-
ataPk = await getAssociatedTokenAccountAddress(token.tokenAddress, recipient.ownerAddress);
166+
ataPk = await getAssociatedTokenAccountAddress(tokenAddress, recipient.ownerAddress);
152167
}
153168

154169
this._instructionsData.push({
155170
type: InstructionBuilderTypes.CreateAssociatedTokenAccount,
156171
params: {
157-
mintAddress: token.tokenAddress,
172+
mintAddress: tokenAddress,
158173
ataAddress: ataPk,
159174
ownerAddress: recipient.ownerAddress,
160175
payerAddress: this._sender,
161176
tokenName: recipient.tokenName,
162-
programId: token.programId,
177+
programId: programId,
163178
},
164179
});
165180
})

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ export interface TokenTransfer {
7272
amount: string;
7373
tokenName: string;
7474
sourceAddress: string;
75+
tokenAddress?: string;
76+
decimalPlaces?: number;
77+
programId?: string;
7578
};
7679
}
7780

@@ -182,4 +185,6 @@ export class TokenAssociateRecipient {
182185
ownerAddress: string;
183186
tokenName: string;
184187
ataAddress?: string;
188+
tokenAddress?: string;
189+
programId?: string;
185190
}

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

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,23 @@ import { getInstructionType } from './utils';
5252
export function instructionParamsFactory(
5353
type: TransactionType,
5454
instructions: TransactionInstruction[],
55-
coinName?: string
55+
coinName?: string,
56+
instructionMetadata?: InstructionParams[],
57+
_useTokenAddressTokenName?: boolean
5658
): InstructionParams[] {
5759
switch (type) {
5860
case TransactionType.WalletInitialization:
5961
return parseWalletInitInstructions(instructions);
6062
case TransactionType.Send:
61-
return parseSendInstructions(instructions);
63+
return parseSendInstructions(instructions, instructionMetadata, _useTokenAddressTokenName);
6264
case TransactionType.StakingActivate:
6365
return parseStakingActivateInstructions(instructions);
6466
case TransactionType.StakingDeactivate:
6567
return parseStakingDeactivateInstructions(instructions, coinName);
6668
case TransactionType.StakingWithdraw:
6769
return parseStakingWithdrawInstructions(instructions);
6870
case TransactionType.AssociatedTokenAccountInitialization:
69-
return parseAtaInitInstructions(instructions);
71+
return parseAtaInitInstructions(instructions, instructionMetadata, _useTokenAddressTokenName);
7072
case TransactionType.CloseAssociatedTokenAccount:
7173
return parseAtaCloseInstructions(instructions);
7274
case TransactionType.StakingAuthorize:
@@ -120,7 +122,9 @@ function parseWalletInitInstructions(instructions: TransactionInstruction[]): Ar
120122
* @returns {InstructionParams[]} An array containing instruction params for Send tx
121123
*/
122124
function parseSendInstructions(
123-
instructions: TransactionInstruction[]
125+
instructions: TransactionInstruction[],
126+
instructionMetadata?: InstructionParams[],
127+
_useTokenAddressTokenName?: boolean
124128
): Array<Nonce | Memo | Transfer | TokenTransfer | AtaInit | AtaClose | SetPriorityFee> {
125129
const instructionData: Array<Nonce | Memo | Transfer | TokenTransfer | AtaInit | AtaClose | SetPriorityFee> = [];
126130
for (const instruction of instructions) {
@@ -160,7 +164,12 @@ function parseSendInstructions(
160164
} else {
161165
tokenTransferInstruction = decodeTransferCheckedInstruction(instruction, TOKEN_2022_PROGRAM_ID);
162166
}
163-
const tokenName = findTokenName(tokenTransferInstruction.keys.mint.pubkey.toString());
167+
const tokenAddress = tokenTransferInstruction.keys.mint.pubkey.toString();
168+
const tokenName = findTokenName(tokenAddress, instructionMetadata, _useTokenAddressTokenName);
169+
let programIDForTokenTransfer: string | undefined;
170+
if (instruction.programId) {
171+
programIDForTokenTransfer = instruction.programId.toString();
172+
}
164173
const tokenTransfer: TokenTransfer = {
165174
type: InstructionBuilderTypes.TokenTransfer,
166175
params: {
@@ -169,13 +178,20 @@ function parseSendInstructions(
169178
amount: tokenTransferInstruction.data.amount.toString(),
170179
tokenName,
171180
sourceAddress: tokenTransferInstruction.keys.source.pubkey.toString(),
181+
tokenAddress: tokenAddress,
182+
programId: programIDForTokenTransfer,
183+
decimalPlaces: tokenTransferInstruction.data.decimals,
172184
},
173185
};
174186
instructionData.push(tokenTransfer);
175187
break;
176188
case ValidInstructionTypesEnum.InitializeAssociatedTokenAccount:
177189
const mintAddress = instruction.keys[ataInitInstructionKeysIndexes.MintAddress].pubkey.toString();
178-
const mintTokenName = findTokenName(mintAddress);
190+
const mintTokenName = findTokenName(mintAddress, instructionMetadata, _useTokenAddressTokenName);
191+
let programID: string | undefined;
192+
if (instruction.programId) {
193+
programID = instruction.programId.toString();
194+
}
179195

180196
const ataInit: AtaInit = {
181197
type: InstructionBuilderTypes.CreateAssociatedTokenAccount,
@@ -185,6 +201,7 @@ function parseSendInstructions(
185201
ownerAddress: instruction.keys[ataInitInstructionKeysIndexes.OwnerAddress].pubkey.toString(),
186202
payerAddress: instruction.keys[ataInitInstructionKeysIndexes.PayerAddress].pubkey.toString(),
187203
tokenName: mintTokenName,
204+
programId: programID,
188205
},
189206
};
190207
instructionData.push(ataInit);
@@ -652,7 +669,11 @@ const closeAtaInstructionKeysIndexes = {
652669
* @param {TransactionInstruction[]} instructions - an array of supported Solana instructions
653670
* @returns {InstructionParams[]} An array containing instruction params for Send tx
654671
*/
655-
function parseAtaInitInstructions(instructions: TransactionInstruction[]): Array<AtaInit | Memo | Nonce> {
672+
function parseAtaInitInstructions(
673+
instructions: TransactionInstruction[],
674+
instructionMetadata?: InstructionParams[],
675+
_useTokenAddressTokenName?: boolean
676+
): Array<AtaInit | Memo | Nonce> {
656677
const instructionData: Array<AtaInit | Memo | Nonce> = [];
657678
let memo: Memo | undefined;
658679

@@ -675,8 +696,11 @@ function parseAtaInitInstructions(instructions: TransactionInstruction[]): Array
675696
break;
676697
case ValidInstructionTypesEnum.InitializeAssociatedTokenAccount:
677698
const mintAddress = instruction.keys[ataInitInstructionKeysIndexes.MintAddress].pubkey.toString();
678-
const tokenName = findTokenName(mintAddress);
679-
699+
const tokenName = findTokenName(mintAddress, instructionMetadata, _useTokenAddressTokenName);
700+
let programID: string | undefined;
701+
if (instruction.programId) {
702+
programID = instruction.programId.toString();
703+
}
680704
const ataInit: AtaInit = {
681705
type: InstructionBuilderTypes.CreateAssociatedTokenAccount,
682706
params: {
@@ -685,6 +709,7 @@ function parseAtaInitInstructions(instructions: TransactionInstruction[]): Array
685709
ownerAddress: instruction.keys[ataInitInstructionKeysIndexes.OwnerAddress].pubkey.toString(),
686710
payerAddress: instruction.keys[ataInitInstructionKeysIndexes.PayerAddress].pubkey.toString(),
687711
tokenName,
712+
programId: programID,
688713
},
689714
};
690715
instructionData.push(ataInit);
@@ -831,7 +856,11 @@ function parseStakingAuthorizeRawInstructions(instructions: TransactionInstructi
831856
return instructionData;
832857
}
833858

834-
function findTokenName(mintAddress: string): string {
859+
function findTokenName(
860+
mintAddress: string,
861+
instructionMetadata?: InstructionParams[],
862+
_useTokenAddressTokenName?: boolean
863+
): string {
835864
let token: string | undefined;
836865

837866
coins.forEach((value, key) => {
@@ -840,6 +869,26 @@ function findTokenName(mintAddress: string): string {
840869
}
841870
});
842871

872+
if (!token && instructionMetadata) {
873+
instructionMetadata.forEach((instruction) => {
874+
if (
875+
instruction.type === InstructionBuilderTypes.CreateAssociatedTokenAccount &&
876+
instruction.params.mintAddress === mintAddress
877+
) {
878+
token = instruction.params.tokenName;
879+
} else if (
880+
instruction.type === InstructionBuilderTypes.TokenTransfer &&
881+
instruction.params.tokenAddress === mintAddress
882+
) {
883+
token = instruction.params.tokenName;
884+
}
885+
});
886+
}
887+
888+
if (!token && _useTokenAddressTokenName) {
889+
token = mintAddress;
890+
}
891+
843892
assert(token);
844893

845894
return token;

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { coins, SolCoin } from '@bitgo/statics';
1+
import { SolCoin } from '@bitgo/statics';
22
import {
33
createAssociatedTokenAccountInstruction,
44
createCloseAccountInstruction,
@@ -35,6 +35,7 @@ import {
3535
WalletInit,
3636
SetPriorityFee,
3737
} from './iface';
38+
import { getSolTokenFromTokenName } from './utils';
3839

3940
/**
4041
* Construct Solana instructions from instructions params
@@ -157,28 +158,43 @@ function tokenTransferInstruction(data: TokenTransfer): TransactionInstruction[]
157158
assert(amount, 'Missing amount param');
158159
assert(tokenName, 'Missing token name');
159160
assert(sourceAddress, 'Missing ata address');
160-
const token = coins.get(data.params.tokenName);
161-
assert(token instanceof SolCoin);
161+
const token = getSolTokenFromTokenName(data.params.tokenName);
162+
let tokenAddress: string;
163+
let programId: string | undefined;
164+
let decimalPlaces: number;
165+
if (data.params.tokenAddress && data.params.decimalPlaces) {
166+
tokenAddress = data.params.tokenAddress;
167+
decimalPlaces = data.params.decimalPlaces;
168+
programId = data.params.programId;
169+
} else if (token) {
170+
assert(token instanceof SolCoin);
171+
tokenAddress = token.tokenAddress;
172+
decimalPlaces = token.decimalPlaces;
173+
programId = token.programId;
174+
} else {
175+
throw new Error('Invalid token name, got:' + data.params.tokenName);
176+
}
177+
162178
let transferInstruction: TransactionInstruction;
163-
if (token.programId === TOKEN_2022_PROGRAM_ID.toString()) {
179+
if (programId === TOKEN_2022_PROGRAM_ID.toString()) {
164180
transferInstruction = createTransferCheckedInstruction(
165181
new PublicKey(sourceAddress),
166-
new PublicKey(token.tokenAddress),
182+
new PublicKey(tokenAddress),
167183
new PublicKey(toAddress),
168184
new PublicKey(fromAddress),
169185
BigInt(amount),
170-
token.decimalPlaces,
186+
decimalPlaces,
171187
[],
172188
TOKEN_2022_PROGRAM_ID
173189
);
174190
} else {
175191
transferInstruction = createTransferCheckedInstruction(
176192
new PublicKey(sourceAddress),
177-
new PublicKey(token.tokenAddress),
193+
new PublicKey(tokenAddress),
178194
new PublicKey(toAddress),
179195
new PublicKey(fromAddress),
180196
BigInt(amount),
181-
token.decimalPlaces
197+
decimalPlaces
182198
);
183199
}
184200
return [transferInstruction];

0 commit comments

Comments
 (0)