@prism-hq/prism-ag
Version:
Prism Aggregator
289 lines (288 loc) • 15.9 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseMeta = exports.applyBlockHashAndPartialSign = exports.generateFeesAccount = exports.prepareAccounts = exports.getTokenAccountAddressByMint = exports.createAssociatedTokenAccountIfNotExist = exports.createTokenAccountIfNotExist = exports.createProgramAccountIfNotExist = exports.createSyncNativeInstruction = void 0;
const token_instructions_1 = require("@project-serum/serum/lib/token-instructions");
const spl_token_1 = require("@solana/spl-token");
const web3_js_1 = require("@solana/web3.js");
// import { RouteData } from "@symmetry-hq/liquidity-sdk/dist/types";
const borsh_1 = require("@project-serum/borsh");
const types_1 = require("../types/types");
function createSyncNativeInstruction(nativeAccount) {
const dataLayout = (0, borsh_1.struct)([
(0, borsh_1.u8)("instruction"),
]);
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode({
instruction: 17, // SyncNative instruction
}, data);
const keys = [{ pubkey: nativeAccount, isSigner: false, isWritable: true }];
return new web3_js_1.TransactionInstruction({
keys,
programId: spl_token_1.TOKEN_PROGRAM_ID,
data,
});
}
exports.createSyncNativeInstruction = createSyncNativeInstruction;
function createProgramAccountIfNotExist(connection, account, owner, programId, lamports, layout, transaction, signer) {
return __awaiter(this, void 0, void 0, function* () {
let publicKey;
if (account) {
publicKey = new web3_js_1.PublicKey(account);
}
else {
const newAccount = new web3_js_1.Account();
publicKey = newAccount.publicKey;
transaction.add(web3_js_1.SystemProgram.createAccount({
fromPubkey: owner,
newAccountPubkey: publicKey,
lamports: lamports !== null && lamports !== void 0 ? lamports : (yield connection.getMinimumBalanceForRentExemption(layout.span)),
space: layout.span,
programId
}));
signer.push(newAccount);
}
return publicKey;
});
}
exports.createProgramAccountIfNotExist = createProgramAccountIfNotExist;
function createTokenAccountIfNotExist(connection, account, owner, mintAddress, lamports, transaction, signer) {
return __awaiter(this, void 0, void 0, function* () {
let publicKey;
if (account) {
publicKey = new web3_js_1.PublicKey(account);
}
else {
publicKey = yield createProgramAccountIfNotExist(connection, account, owner, spl_token_1.TOKEN_PROGRAM_ID, lamports, types_1.ACCOUNT_LAYOUT, transaction, signer);
transaction.add((0, token_instructions_1.initializeAccount)({
account: publicKey,
mint: new web3_js_1.PublicKey(mintAddress),
owner
}));
}
return publicKey;
});
}
exports.createTokenAccountIfNotExist = createTokenAccountIfNotExist;
function createAssociatedTokenAccountIfNotExist(account, owner, mintAddress, connection, transaction, atas = []) {
return __awaiter(this, void 0, void 0, function* () {
let publicKey;
if (account) {
publicKey = new web3_js_1.PublicKey(account);
}
const mint = new web3_js_1.PublicKey(mintAddress);
// @ts-ignore without ts ignore, yarn build will failed
const ata = yield spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, mint, owner, true);
const infoAta = yield connection.getAccountInfo(ata);
if ((!publicKey || !ata.equals(publicKey)) && !atas.includes(ata.toBase58()) && !infoAta) {
transaction.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'), spl_token_1.TOKEN_PROGRAM_ID, mint, ata, owner, owner));
atas.push(ata.toBase58());
}
return ata;
});
}
exports.createAssociatedTokenAccountIfNotExist = createAssociatedTokenAccountIfNotExist;
function getTokenAccountAddressByMint(accounts, coin) {
if (!coin)
return null;
for (let i = 0; i < accounts.length; i++)
if (accounts[i].mint == coin.mintAddress)
return accounts[i].address;
return null;
}
exports.getTokenAccountAddressByMint = getTokenAccountAddressByMint;
function prepareAccounts(user, userAccounts, connection, route, preTransaction, preSigners, postTransaction, unWrapSol) {
return __awaiter(this, void 0, void 0, function* () {
let { fromCoin, midCoin, toCoin } = route.routeData;
let midAccount = getTokenAccountAddressByMint(userAccounts, midCoin);
let fromAccount = getTokenAccountAddressByMint(userAccounts, fromCoin);
let toAccount = getTokenAccountAddressByMint(userAccounts, toCoin);
if (fromCoin.mintAddress === "So11111111111111111111111111111111111111112") {
fromAccount = yield createAssociatedTokenAccountIfNotExist(fromAccount, user, fromCoin.mintAddress, connection, preTransaction);
if (unWrapSol) {
preTransaction.add(web3_js_1.SystemProgram.transfer({
fromPubkey: user,
toPubkey: fromAccount,
lamports: Math.floor(route.amountIn * 1e9 + 1e7), // 1 sol
}));
preTransaction.add(createSyncNativeInstruction(fromAccount));
postTransaction.add((0, token_instructions_1.closeAccount)({
source: fromAccount,
destination: user,
owner: user
}));
}
}
else
fromAccount = yield createAssociatedTokenAccountIfNotExist(fromAccount, user, fromCoin.mintAddress, connection, preTransaction);
if (toCoin.mintAddress === "So11111111111111111111111111111111111111112") {
toAccount = yield createAssociatedTokenAccountIfNotExist(toAccount, user, toCoin.mintAddress, connection, preTransaction);
if (unWrapSol) {
postTransaction.add((0, token_instructions_1.closeAccount)({
source: toAccount,
destination: user,
owner: user
}));
}
}
else
toAccount = yield createAssociatedTokenAccountIfNotExist(toAccount, user, toCoin.mintAddress, connection, preTransaction);
if (midCoin) {
if (midCoin.mintAddress === "So11111111111111111111111111111111111111112") {
midAccount = yield createAssociatedTokenAccountIfNotExist(midAccount, user, midCoin.mintAddress, connection, preTransaction);
postTransaction.add((0, token_instructions_1.closeAccount)({
source: midAccount,
destination: user,
owner: user,
}));
}
else
midAccount = yield createAssociatedTokenAccountIfNotExist(midAccount, user, midCoin.mintAddress, connection, preTransaction);
}
return {
fromTokenAccount: fromAccount,
midTokenAccount: midAccount,
toTokenAccount: toAccount,
};
});
}
exports.prepareAccounts = prepareAccounts;
function generateFeesAccount(connection, settings, user, mint, preTransaction, route) {
return __awaiter(this, void 0, void 0, function* () {
if (!mint)
return null;
let owner = yield spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mint), settings.owner.publicKey);
const info = yield connection.getAccountInfo(owner);
if (!info) {
preTransaction.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mint), owner, settings.owner.publicKey, user));
}
let host = yield spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mint), settings.host.publicKey);
if (!settings.host.publicKey.equals(settings.owner.publicKey)) {
const infoHost = yield connection.getAccountInfo(host);
if (!infoHost) {
preTransaction.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mint), host, settings.host.publicKey, user));
}
}
if (route.provider == "symmetry") {
let symmetryInfo = route.routeData.symmetryInfo;
let swapAccounts = symmetryInfo.swapAccounts;
let swapFeeAccount = yield spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, swapAccounts.fees.feeTokenMint, swapAccounts.fees.smfWallet);
let hostFeeAccount = yield spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, swapAccounts.fees.feeTokenMint, swapAccounts.fees.hostWallet);
let managerFeeAccount = yield spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, swapAccounts.fees.feeTokenMint, swapAccounts.fees.managerWallet);
if (!swapFeeAccount.equals(owner) && !swapFeeAccount.equals(host)) {
const infoHost = yield connection.getAccountInfo(swapFeeAccount);
if (!infoHost) {
preTransaction.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, swapAccounts.fees.feeTokenMint, swapFeeAccount, swapAccounts.fees.smfWallet, user));
}
}
if (!hostFeeAccount.equals(owner) && !hostFeeAccount.equals(host) && !hostFeeAccount.equals(swapFeeAccount)) {
const infoHost = yield connection.getAccountInfo(hostFeeAccount);
if (!infoHost) {
preTransaction.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, swapAccounts.fees.feeTokenMint, hostFeeAccount, swapAccounts.fees.hostWallet, user));
}
}
if (!managerFeeAccount.equals(owner) && !managerFeeAccount.equals(host) && !managerFeeAccount.equals(swapFeeAccount) && !managerFeeAccount.equals(hostFeeAccount)) {
const infoHost = yield connection.getAccountInfo(managerFeeAccount);
if (!infoHost) {
preTransaction.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, swapAccounts.fees.feeTokenMint, managerFeeAccount, swapAccounts.fees.managerWallet, user));
}
}
}
return {
owner: owner,
host: host,
};
});
}
exports.generateFeesAccount = generateFeesAccount;
function applyBlockHashAndPartialSign(connection, wallet, preTransaction, transaction, postTransaction, preSigners, signers) {
return __awaiter(this, void 0, void 0, function* () {
let { blockhash } = yield connection.getRecentBlockhash('processed');
let result = [];
let txIndex = 0;
if (preTransaction.instructions.length > 0) {
txIndex = 1;
preTransaction.recentBlockhash = blockhash;
preTransaction.feePayer = wallet.publicKey;
preTransaction.setSigners(wallet.publicKey, ...preSigners.map((s) => s.publicKey));
if (preSigners.length > 0)
preTransaction.partialSign(...preSigners);
result.push(preTransaction);
}
transaction.recentBlockhash = blockhash;
transaction.feePayer = wallet.publicKey;
transaction.setSigners(wallet.publicKey, ...signers.map((s) => s.publicKey));
if (signers.length > 0)
transaction.partialSign(...signers);
result.push(transaction);
if (postTransaction.instructions.length > 0) {
postTransaction.recentBlockhash = blockhash;
postTransaction.feePayer = wallet.publicKey;
postTransaction.setSigners(wallet.publicKey, ...signers.map((s) => s.publicKey));
if (signers.length > 0)
postTransaction.partialSign(...signers);
result.push(postTransaction);
}
return {
txIndex: txIndex,
transactions: result
};
});
}
exports.applyBlockHashAndPartialSign = applyBlockHashAndPartialSign;
function parseMeta(response, txId, swapResult) {
return __awaiter(this, void 0, void 0, function* () {
try {
let { fromMint, toMint, midMint, from, to, mid } = swapResult;
let meta = response.meta;
if (response.meta.err)
return {
status: "Error",
error: response.meta.err,
};
let { postBalances, preTokenBalances, postTokenBalances } = meta;
let maxFrom = 0;
let maxTo = 0;
let balances = [];
for (let i = 0; i < postBalances.length; i++)
balances.push({ pre: 0, post: 0, mint: "" });
for (let i = 0; i < preTokenBalances.length; i++) {
balances[preTokenBalances[i].accountIndex].pre = preTokenBalances[i].uiTokenAmount.uiAmount;
balances[preTokenBalances[i].accountIndex].mint = preTokenBalances[i].mint;
}
for (let i = 0; i < postTokenBalances.length; i++) {
balances[postTokenBalances[i].accountIndex].post = postTokenBalances[i].uiTokenAmount.uiAmount;
balances[postTokenBalances[i].accountIndex].mint = postTokenBalances[i].mint;
}
for (let i = 0; i < postBalances.length; i++) {
if (balances[i].mint == fromMint && balances[i].post - balances[i].pre < maxFrom)
maxFrom = balances[i].post - balances[i].pre;
if (balances[i].mint == toMint && balances[i].post - balances[i].pre > maxTo)
maxTo = balances[i].post - balances[i].pre;
}
return {
status: "Parsed",
from: from,
to: to,
fromAmount: parseFloat((-maxFrom.toFixed(9)).toString()),
fromMint: fromMint,
toAmount: parseFloat(maxTo.toFixed(9).toString()),
toMint: toMint,
rateA: parseFloat(((maxFrom == 0 ? 0 : -maxTo / maxFrom).toFixed(9)).toString()),
rateB: parseFloat((maxTo == 0 ? 0 : -maxFrom / maxTo).toFixed(9).toString()),
txId: txId,
};
}
catch (e) {
}
});
}
exports.parseMeta = parseMeta;