Skip to content

Commit

Permalink
STREAM-1454: support Token2022 (#162)
Browse files Browse the repository at this point in the history
* STREAM-1454: support Token2022
  • Loading branch information
Yolley committed Apr 8, 2024
1 parent 1104b99 commit 06f6635
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 50 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"packages": [
"packages/*"
],
"version": "6.1.2",
"version": "6.2.0",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@streamflow/common",
"version": "6.1.2",
"version": "6.2.0",
"description": "Common utilities and types used by streamflow packages.",
"homepage": "https://github.com/streamflow-finance/js-sdk/",
"main": "dist/index.js",
Expand Down
11 changes: 7 additions & 4 deletions packages/common/solana/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,8 @@ export async function enrichAtaParams(connection: Connection, paramsBatch: AtaPa
}
const mintStr = params.mint.toString();
if (!(mintStr in programIdByMint)) {
const { programId } = await getMintAndProgram(connection, params.mint);
programIdByMint[mintStr] = programId;
const { tokenProgramId } = await getMintAndProgram(connection, params.mint);
programIdByMint[mintStr] = tokenProgramId;
}
params.programId = programIdByMint[mintStr];
return params;
Expand Down Expand Up @@ -445,6 +445,9 @@ export async function checkOrCreateAtaBatch(
programId?: PublicKey,
): Promise<TransactionInstruction[]> {
const ixs: TransactionInstruction[] = [];
if (!programId) {
programId = (await getMintAndProgram(connection, mint)).tokenProgramId;
}
// TODO: optimize fetching and maps/arrays
const atas: PublicKey[] = [];
for (const owner of owners) {
Expand Down Expand Up @@ -493,14 +496,14 @@ export async function getMintAndProgram(
connection: Connection,
address: PublicKey,
commitment?: Commitment,
): Promise<{ mint: Mint; programId: PublicKey }> {
): Promise<{ mint: Mint; tokenProgramId: PublicKey }> {
const accountInfo = await connection.getAccountInfo(address, commitment);
let programId = accountInfo?.owner;
if (!programId?.equals(TOKEN_PROGRAM_ID) && !programId?.equals(TOKEN_2022_PROGRAM_ID)) {
programId = TOKEN_PROGRAM_ID;
}
return {
mint: unpackMint(address, accountInfo, programId),
programId: programId!,
tokenProgramId: programId!,
};
}
2 changes: 1 addition & 1 deletion packages/distributor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@streamflow/distributor",
"version": "6.1.2",
"version": "6.2.0",
"description": "JavaScript SDK to interact with Streamflow Airdrop protocol.",
"homepage": "https://github.com/streamflow-finance/js-sdk/",
"main": "dist/index.js",
Expand Down
24 changes: 12 additions & 12 deletions packages/distributor/solana/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ export default class SolanaDistributorClient {

const ixs: TransactionInstruction[] = prepareBaseInstructions(this.connection, { computePrice, computeLimit });
const mint = isNative ? NATIVE_MINT : new PublicKey(data.mint);
const { mint: mintAccount, programId } = await getMintAndProgram(this.connection, mint);
const { mint: mintAccount, tokenProgramId } = await getMintAndProgram(this.connection, mint);
const distributorPublicKey = getDistributorPda(this.programId, mint, data.version);
const tokenVault = await ata(mint, distributorPublicKey, programId);
const senderTokens = await ata(mint, invoker.publicKey, programId);
const tokenVault = await ata(mint, distributorPublicKey, tokenProgramId);
const senderTokens = await ata(mint, invoker.publicKey, tokenProgramId);

const args: NewDistributorArgs = {
version: new BN(data.version, 10),
Expand All @@ -105,7 +105,7 @@ export default class SolanaDistributorClient {
admin: invoker.publicKey,
systemProgram: SystemProgram.programId,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
tokenProgram: programId,
tokenProgram: tokenProgramId,
};

if (isNative) {
Expand All @@ -129,7 +129,7 @@ export default class SolanaDistributorClient {
BigInt(data.maxTotalClaim.toString()),
mintAccount.decimals,
undefined,
programId,
tokenProgramId,
),
);

Expand Down Expand Up @@ -162,12 +162,12 @@ export default class SolanaDistributorClient {
throw new Error("Couldn't get account info");
}

const { programId } = await getMintAndProgram(this.connection, distributor.mint);
const { tokenProgramId } = await getMintAndProgram(this.connection, distributor.mint);
const ixs: TransactionInstruction[] = prepareBaseInstructions(this.connection, { computePrice, computeLimit });
ixs.push(
...(await checkOrCreateAtaBatch(this.connection, [invoker.publicKey], distributor.mint, invoker, programId)),
...(await checkOrCreateAtaBatch(this.connection, [invoker.publicKey], distributor.mint, invoker, tokenProgramId)),
);
const invokerTokens = await ata(distributor.mint, invoker.publicKey, programId);
const invokerTokens = await ata(distributor.mint, invoker.publicKey, tokenProgramId);
const claimStatusPublicKey = getClaimantStatusPda(this.programId, distributorPublicKey, invoker.publicKey);
const claimStatus = await ClaimStatus.fetch(this.connection, claimStatusPublicKey);

Expand All @@ -178,7 +178,7 @@ export default class SolanaDistributorClient {
to: invokerTokens,
claimant: invoker.publicKey,
mint: distributor.mint,
tokenProgram: programId,
tokenProgram: tokenProgramId,
systemProgram: SystemProgram.programId,
};

Expand Down Expand Up @@ -221,10 +221,10 @@ export default class SolanaDistributorClient {
throw new Error("Couldn't get account info");
}

const { programId } = await getMintAndProgram(this.connection, distributor.mint);
const { tokenProgramId } = await getMintAndProgram(this.connection, distributor.mint);
const ixs: TransactionInstruction[] = prepareBaseInstructions(this.connection, { computePrice, computeLimit });
ixs.push(
...(await checkOrCreateAtaBatch(this.connection, [invoker.publicKey], distributor.mint, invoker, programId)),
...(await checkOrCreateAtaBatch(this.connection, [invoker.publicKey], distributor.mint, invoker, tokenProgramId)),
);
const accounts: ClawbackAccounts = {
distributor: distributorPublicKey,
Expand All @@ -233,7 +233,7 @@ export default class SolanaDistributorClient {
admin: invoker.publicKey,
mint: distributor.mint,
systemProgram: SystemProgram.programId,
tokenProgram: programId,
tokenProgram: tokenProgramId,
};

ixs.push(clawback(accounts, this.programId));
Expand Down
2 changes: 1 addition & 1 deletion packages/stream/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@streamflow/stream",
"version": "6.1.2",
"version": "6.2.0",
"description": "JavaScript SDK to interact with Streamflow protocol.",
"homepage": "https://github.com/streamflow-finance/js-sdk/",
"main": "dist/index.js",
Expand Down
67 changes: 37 additions & 30 deletions packages/stream/solana/StreamClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import BN from "bn.js";
import { Buffer } from "buffer";
import { ASSOCIATED_TOKEN_PROGRAM_ID, NATIVE_MINT, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { ASSOCIATED_TOKEN_PROGRAM_ID, NATIVE_MINT } from "@solana/spl-token";
import {
Connection,
Keypair,
Expand All @@ -24,6 +24,7 @@ import {
prepareWrappedAccount,
prepareTransaction,
prepareBaseInstructions,
getMintAndProgram,
} from "@streamflow/common/solana";
import * as borsh from "borsh";

Expand Down Expand Up @@ -199,13 +200,14 @@ export default class SolanaStreamClient extends BaseStreamClient {
this.programId,
);

const senderTokens = await ata(mintPublicKey, sender.publicKey);
const recipientTokens = await ata(mintPublicKey, recipientPublicKey);
const streamflowTreasuryTokens = await ata(mintPublicKey, STREAMFLOW_TREASURY_PUBLIC_KEY);
const { tokenProgramId } = await getMintAndProgram(this.connection, mintPublicKey);
const senderTokens = await ata(mintPublicKey, sender.publicKey, tokenProgramId);
const recipientTokens = await ata(mintPublicKey, recipientPublicKey, tokenProgramId);
const streamflowTreasuryTokens = await ata(mintPublicKey, STREAMFLOW_TREASURY_PUBLIC_KEY, tokenProgramId);

const partnerPublicKey = partner ? new PublicKey(partner) : STREAMFLOW_TREASURY_PUBLIC_KEY;

const partnerTokens = await ata(mintPublicKey, partnerPublicKey);
const partnerTokens = await ata(mintPublicKey, partnerPublicKey, tokenProgramId);

if (isNative) {
const totalFee = await this.getTotalFee({
Expand Down Expand Up @@ -249,7 +251,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
feeOracle: FEE_ORACLE_PUBLIC_KEY,
rent: SYSVAR_RENT_PUBKEY,
timelockProgram: this.programId,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
withdrawor: WITHDRAWOR_PUBLIC_KEY,
systemProgram: SystemProgram.programId,
Expand Down Expand Up @@ -339,7 +341,8 @@ export default class SolanaStreamClient extends BaseStreamClient {
this.programId,
);

const senderTokens = await ata(mintPublicKey, sender.publicKey);
const { tokenProgramId } = await getMintAndProgram(this.connection, mintPublicKey);
const senderTokens = await ata(mintPublicKey, sender.publicKey, tokenProgramId);

const partnerPublicKey = partner ? new PublicKey(partner) : STREAMFLOW_TREASURY_PUBLIC_KEY;

Expand Down Expand Up @@ -382,7 +385,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
feeOracle: FEE_ORACLE_PUBLIC_KEY,
rent: SYSVAR_RENT_PUBKEY,
timelockProgram: this.programId,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
withdrawor: WITHDRAWOR_PUBLIC_KEY,
systemProgram: SystemProgram.programId,
},
Expand Down Expand Up @@ -554,9 +557,10 @@ export default class SolanaStreamClient extends BaseStreamClient {
}

const data = decodeStream(escrow.data);
const streamflowTreasuryTokens = await ata(data.mint, STREAMFLOW_TREASURY_PUBLIC_KEY);
const partnerTokens = await ata(data.mint, data.partner);
await this.checkAssociatedTokenAccounts(data, { invoker, checkTokenAccounts }, ixs);
const { tokenProgramId } = await getMintAndProgram(this.connection, data.mint);
const streamflowTreasuryTokens = await ata(data.mint, STREAMFLOW_TREASURY_PUBLIC_KEY, tokenProgramId);
const partnerTokens = await ata(data.mint, data.partner, tokenProgramId);
await this.checkAssociatedTokenAccounts(data, { invoker, checkTokenAccounts }, ixs, tokenProgramId);

ixs.push(
withdrawStreamInstruction(amount, this.programId, {
Expand All @@ -570,7 +574,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
partner: data.partner,
partnerTokens,
mint: data.mint,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
}),
);

Expand Down Expand Up @@ -611,14 +615,15 @@ export default class SolanaStreamClient extends BaseStreamClient {

const data = decodeStream(escrowAcc?.data);

const streamflowTreasuryTokens = await ata(data.mint, STREAMFLOW_TREASURY_PUBLIC_KEY);
const partnerTokens = await ata(data.mint, data.partner);
const { tokenProgramId } = await getMintAndProgram(this.connection, data.mint);
const streamflowTreasuryTokens = await ata(data.mint, STREAMFLOW_TREASURY_PUBLIC_KEY, tokenProgramId);
const partnerTokens = await ata(data.mint, data.partner, tokenProgramId);

const ixs: TransactionInstruction[] = prepareBaseInstructions(this.connection, {
computePrice,
computeLimit,
});
await this.checkAssociatedTokenAccounts(data, { invoker, checkTokenAccounts }, ixs);
await this.checkAssociatedTokenAccounts(data, { invoker, checkTokenAccounts }, ixs, tokenProgramId);

ixs.push(
cancelStreamInstruction(this.programId, {
Expand All @@ -634,7 +639,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
partner: data.partner,
partnerTokens,
mint: data.mint,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
}),
);

Expand Down Expand Up @@ -683,8 +688,9 @@ export default class SolanaStreamClient extends BaseStreamClient {
throw new Error("Couldn't get account info");
}
const { mint } = decodeStream(escrow?.data);
const { tokenProgramId } = await getMintAndProgram(this.connection, mint);

const newRecipientTokens = await ata(mint, newRecipientPublicKey);
const newRecipientTokens = await ata(mint, newRecipientPublicKey, tokenProgramId);

ixs.push(
transferStreamInstruction(this.programId, {
Expand All @@ -694,7 +700,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
metadata: stream,
mint,
rent: SYSVAR_RENT_PUBKEY,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
}),
Expand Down Expand Up @@ -740,8 +746,9 @@ export default class SolanaStreamClient extends BaseStreamClient {
}
const { mint, partner, senderTokens, escrowTokens } = decodeStream(escrow?.data);

const streamflowTreasuryTokens = await ata(mint, STREAMFLOW_TREASURY_PUBLIC_KEY);
const partnerTokens = await ata(mint, partner);
const { tokenProgramId } = await getMintAndProgram(this.connection, mint);
const streamflowTreasuryTokens = await ata(mint, STREAMFLOW_TREASURY_PUBLIC_KEY, tokenProgramId);
const partnerTokens = await ata(mint, partner, tokenProgramId);

if (isNative) {
ixs.push(...(await prepareWrappedAccount(this.connection, invoker.publicKey, amount)));
Expand All @@ -758,7 +765,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
partner: partner,
partnerTokens: partnerTokens,
mint,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
withdrawor: WITHDRAWOR_PUBLIC_KEY,
systemProgram: SystemProgram.programId,
}),
Expand Down Expand Up @@ -949,13 +956,12 @@ export default class SolanaStreamClient extends BaseStreamClient {
this.programId,
);

const senderTokens = await ata(mintPublicKey, sender.publicKey);
const recipientTokens = await ata(mintPublicKey, recipientPublicKey);
const streamflowTreasuryTokens = await ata(mintPublicKey, STREAMFLOW_TREASURY_PUBLIC_KEY);

const partnerPublicKey = partner ? new PublicKey(partner) : STREAMFLOW_TREASURY_PUBLIC_KEY;

const partnerTokens = await ata(mintPublicKey, partnerPublicKey);
const { tokenProgramId } = await getMintAndProgram(this.connection, mintPublicKey);
const senderTokens = await ata(mintPublicKey, sender.publicKey, tokenProgramId);
const recipientTokens = await ata(mintPublicKey, recipientPublicKey, tokenProgramId);
const streamflowTreasuryTokens = await ata(mintPublicKey, STREAMFLOW_TREASURY_PUBLIC_KEY, tokenProgramId);
const partnerPublicKey = partner ? new PublicKey(partner) : WITHDRAWOR_PUBLIC_KEY;
const partnerTokens = await ata(mintPublicKey, partnerPublicKey, tokenProgramId);

ixs.push(
createStreamInstruction(
Expand Down Expand Up @@ -991,7 +997,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
feeOracle: FEE_ORACLE_PUBLIC_KEY,
rent: SYSVAR_RENT_PUBKEY,
timelockProgram: this.programId,
tokenProgram: TOKEN_PROGRAM_ID,
tokenProgram: tokenProgramId,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
withdrawor: WITHDRAWOR_PUBLIC_KEY,
systemProgram: SystemProgram.programId,
Expand Down Expand Up @@ -1025,6 +1031,7 @@ export default class SolanaStreamClient extends BaseStreamClient {
data: CheckAssociatedTokenAccountsData,
{ invoker, checkTokenAccounts }: IInteractStreamSolanaExt,
ixs: TransactionInstruction[],
programId: PublicKey,
) {
if (!checkTokenAccounts) {
return;
Expand All @@ -1038,6 +1045,6 @@ export default class SolanaStreamClient extends BaseStreamClient {
]),
(address) => new PublicKey(address),
);
ixs.push(...(await checkOrCreateAtaBatch(this.connection, owners, data.mint, invoker)));
ixs.push(...(await checkOrCreateAtaBatch(this.connection, owners, data.mint, invoker, programId)));
}
}

0 comments on commit 06f6635

Please sign in to comment.