diff --git a/dev.html b/dev.html
index 71c7c0a..64ba790 100644
--- a/dev.html
+++ b/dev.html
@@ -8,10 +8,10 @@
-
+
-
-
+
+
diff --git a/dist/esm/index.evm.js b/dist/esm/index.evm.js
index 68ffa77..255e09a 100644
--- a/dist/esm/index.evm.js
+++ b/dist/esm/index.evm.js
@@ -306,7 +306,10 @@ const route$1 = ({
let amounts; // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch (e) { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
diff --git a/dist/esm/index.js b/dist/esm/index.js
index ab539dd..f8da0d4 100644
--- a/dist/esm/index.js
+++ b/dist/esm/index.js
@@ -2,10 +2,10 @@ import Token from '@depay/web3-tokens';
import { request, getProvider } from '@depay/web3-client';
import { ethers } from 'ethers';
import Blockchains from '@depay/web3-blockchains';
-import { BN, struct, publicKey, u128, u64 as u64$1, seq, u8, u16, i32, bool, i128, PublicKey, Buffer, Keypair, SystemProgram, TransactionInstruction } from '@depay/solana-web3.js';
+import { BN, struct, publicKey, u128, u64 as u64$1, seq, u8, u16, i32, bool, i128, PublicKey, Buffer, Keypair, SystemProgram, TransactionInstruction, blob, u32 } from '@depay/solana-web3.js';
import Decimal from 'decimal.js';
-function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
+function _optionalChain$7(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
constructor({
blockchain,
tokenIn,
@@ -31,10 +31,10 @@ function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[
this.decimalsOut = decimalsOut;
this.path = path;
this.pools = pools;
- this.amountIn = _optionalChain$5([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
- this.amountOutMin = _optionalChain$5([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
- this.amountOut = _optionalChain$5([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
- this.amountInMax = _optionalChain$5([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
+ this.amountIn = _optionalChain$7([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
+ this.amountOutMin = _optionalChain$7([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
+ this.amountOut = _optionalChain$7([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
+ this.amountInMax = _optionalChain$7([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
this.exchange = exchange;
this.getPrep = getPrep;
this.getTransaction = getTransaction;
@@ -308,7 +308,10 @@ const route$1 = ({
let amounts; // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch (e) { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
@@ -432,7 +435,7 @@ class Exchange {
}
}
-function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+function _optionalChain$6(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
// Replaces 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE with the wrapped token and implies wrapping.
//
@@ -440,7 +443,7 @@ function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[
// to be able to differentiate between ETH<>Token and WETH<>Token swaps
// as they are not the same!
//
-const getExchangePath$4 = ({ blockchain, exchange, path }) => {
+const getExchangePath$5 = ({ blockchain, exchange, path }) => {
if(!path) { return }
let exchangePath = path.map((token, index) => {
if (
@@ -472,8 +475,8 @@ const minReserveRequirements = ({ reserves, min, token, token0, token1, decimals
}
};
-const pathExists$5 = async ({ blockchain, exchange, path }) => {
- const exchangePath = getExchangePath$4({ blockchain, exchange, path });
+const pathExists$6 = async ({ blockchain, exchange, path }) => {
+ const exchangePath = getExchangePath$5({ blockchain, exchange, path });
if(!exchangePath || exchangePath.length === 1) { return false }
try {
let pair = await request({
@@ -482,7 +485,7 @@ const pathExists$5 = async ({ blockchain, exchange, path }) => {
method: 'getPair',
api: exchange[blockchain].factory.api,
cache: 3600000,
- params: getExchangePath$4({ blockchain, exchange, path }),
+ params: getExchangePath$5({ blockchain, exchange, path }),
});
if(!pair || pair == Blockchains[blockchain].zero) { return false }
let [reserves, token0, token1] = await Promise.all([
@@ -503,61 +506,61 @@ const pathExists$5 = async ({ blockchain, exchange, path }) => {
} catch (e){ console.log('e', e); return false }
};
-const findPath$5 = async ({ blockchain, exchange, tokenIn, tokenOut }) => {
+const findPath$6 = async ({ blockchain, exchange, tokenIn, tokenOut }) => {
if(
[tokenIn, tokenOut].includes(Blockchains[blockchain].currency.address) &&
[tokenIn, tokenOut].includes(Blockchains[blockchain].wrapped.address)
) { return { path: undefined, exchangePath: undefined } }
let path;
- if (await pathExists$5({ blockchain, exchange, path: [tokenIn, tokenOut] })) {
+ if (await pathExists$6({ blockchain, exchange, path: [tokenIn, tokenOut] })) {
// direct path
path = [tokenIn, tokenOut];
} else if (
tokenIn != Blockchains[blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [tokenIn, Blockchains[blockchain].wrapped.address] }) &&
+ await pathExists$6({ blockchain, exchange, path: [tokenIn, Blockchains[blockchain].wrapped.address] }) &&
tokenOut != Blockchains[blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [tokenOut, Blockchains[blockchain].wrapped.address] })
+ await pathExists$6({ blockchain, exchange, path: [tokenOut, Blockchains[blockchain].wrapped.address] })
) {
// path via WRAPPED
path = [tokenIn, Blockchains[blockchain].wrapped.address, tokenOut];
} else if (
!Blockchains[blockchain].stables.usd.includes(tokenIn) &&
- (await Promise.all(Blockchains[blockchain].stables.usd.map((stable)=>pathExists$5({ blockchain, exchange, path: [tokenIn, stable] })))).filter(Boolean).length &&
+ (await Promise.all(Blockchains[blockchain].stables.usd.map((stable)=>pathExists$6({ blockchain, exchange, path: [tokenIn, stable] })))).filter(Boolean).length &&
tokenOut != Blockchains[blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [Blockchains[blockchain].wrapped.address, tokenOut] })
+ await pathExists$6({ blockchain, exchange, path: [Blockchains[blockchain].wrapped.address, tokenOut] })
) {
// path via tokenIn -> USD -> WRAPPED -> tokenOut
- let USD = (await Promise.all(Blockchains[blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$5({ blockchain, exchange, path: [tokenIn, stable] }) ? stable : undefined) }))).find(Boolean);
+ let USD = (await Promise.all(Blockchains[blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$6({ blockchain, exchange, path: [tokenIn, stable] }) ? stable : undefined) }))).find(Boolean);
path = [tokenIn, USD, Blockchains[blockchain].wrapped.address, tokenOut];
} else if (
tokenIn != Blockchains[blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [tokenIn, Blockchains[blockchain].wrapped.address] }) &&
+ await pathExists$6({ blockchain, exchange, path: [tokenIn, Blockchains[blockchain].wrapped.address] }) &&
!Blockchains[blockchain].stables.usd.includes(tokenOut) &&
- (await Promise.all(Blockchains[blockchain].stables.usd.map((stable)=>pathExists$5({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
+ (await Promise.all(Blockchains[blockchain].stables.usd.map((stable)=>pathExists$6({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
) {
// path via tokenIn -> WRAPPED -> USD -> tokenOut
- let USD = (await Promise.all(Blockchains[blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$5({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
+ let USD = (await Promise.all(Blockchains[blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$6({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
path = [tokenIn, Blockchains[blockchain].wrapped.address, USD, tokenOut];
} else if (
tokenIn != Blockchains[blockchain].wrapped.address &&
tokenIn === Blockchains[blockchain].currency.address &&
!Blockchains[blockchain].stables.usd.includes(tokenOut) &&
- (await Promise.all(Blockchains[blockchain].stables.usd.map((stable)=>pathExists$5({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
+ (await Promise.all(Blockchains[blockchain].stables.usd.map((stable)=>pathExists$6({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
) {
- let USD = (await Promise.all(Blockchains[blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$5({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
+ let USD = (await Promise.all(Blockchains[blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$6({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
path = [tokenIn, USD, tokenOut];
}
// Add WRAPPED to route path if things start or end with NATIVE
// because that actually reflects how things are routed in reality:
- if(_optionalChain$4([path, 'optionalAccess', _ => _.length]) && path[0] == Blockchains[blockchain].currency.address) {
+ if(_optionalChain$6([path, 'optionalAccess', _ => _.length]) && path[0] == Blockchains[blockchain].currency.address) {
path.splice(1, 0, Blockchains[blockchain].wrapped.address);
- } else if(_optionalChain$4([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == Blockchains[blockchain].currency.address) {
+ } else if(_optionalChain$6([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == Blockchains[blockchain].currency.address) {
path.splice(path.length-1, 0, Blockchains[blockchain].wrapped.address);
}
- return { path, exchangePath: getExchangePath$4({ blockchain, exchange, path }) }
+ return { path, exchangePath: getExchangePath$5({ blockchain, exchange, path }) }
};
let getAmountOut$3 = ({ blockchain, exchange, path, amountIn, tokenIn, tokenOut }) => {
@@ -569,7 +572,7 @@ let getAmountOut$3 = ({ blockchain, exchange, path, amountIn, tokenIn, tokenOut
api: exchange[blockchain].router.api,
params: {
amountIn: amountIn,
- path: getExchangePath$4({ blockchain, exchange, path }),
+ path: getExchangePath$5({ blockchain, exchange, path }),
},
})
.then((amountsOut)=>{
@@ -588,7 +591,7 @@ let getAmountIn$3 = ({ blockchain, exchange, path, amountOut, block }) => {
api: exchange[blockchain].router.api,
params: {
amountOut: amountOut,
- path: getExchangePath$4({ blockchain, exchange, path }),
+ path: getExchangePath$5({ blockchain, exchange, path }),
},
block
})
@@ -597,7 +600,7 @@ let getAmountIn$3 = ({ blockchain, exchange, path, amountOut, block }) => {
})
};
-let getAmounts$5 = async ({
+let getAmounts$6 = async ({
blockchain,
exchange,
path,
@@ -674,7 +677,7 @@ let getPrep$3 = async({
};
-let getTransaction$5 = ({
+let getTransaction$6 = ({
exchange,
blockchain,
path,
@@ -725,7 +728,7 @@ let getTransaction$5 = ({
}
transaction.params = Object.assign({}, transaction.params, {
- path: getExchangePath$4({ blockchain, exchange, path }),
+ path: getExchangePath$5({ blockchain, exchange, path }),
to: account,
deadline: Math.round(Date.now() / 1000) + 60 * 60 * 24, // 24 hours
});
@@ -738,17 +741,17 @@ const FACTORY$3 = [{"inputs":[{"internalType":"address","name":"_feeToSetter","t
const PAIR$1 = [{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"sync","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}];
var UniswapV2 = {
- findPath: findPath$5,
- pathExists: pathExists$5,
- getAmounts: getAmounts$5,
+ findPath: findPath$6,
+ pathExists: pathExists$6,
+ getAmounts: getAmounts$6,
getPrep: getPrep$3,
- getTransaction: getTransaction$5,
+ getTransaction: getTransaction$6,
ROUTER: ROUTER$3,
FACTORY: FACTORY$3,
PAIR: PAIR$1,
};
-const exchange$h = {
+const exchange$i = {
name: 'honeyswap',
label: 'Honeyswap',
@@ -778,13 +781,13 @@ var honeyswap = (scope)=>{
return new Exchange(
- Object.assign(exchange$h, {
+ Object.assign(exchange$i, {
scope,
- findPath: (args)=>UniswapV2.findPath({ ...args, exchange: exchange$h }),
- pathExists: (args)=>UniswapV2.pathExists({ ...args, exchange: exchange$h }),
- getAmounts: (args)=>UniswapV2.getAmounts({ ...args, exchange: exchange$h }),
- getPrep: (args)=>UniswapV2.getPrep({ ...args, exchange: exchange$h }),
- getTransaction: (args)=>UniswapV2.getTransaction({ ...args, exchange: exchange$h }),
+ findPath: (args)=>UniswapV2.findPath({ ...args, exchange: exchange$i }),
+ pathExists: (args)=>UniswapV2.pathExists({ ...args, exchange: exchange$i }),
+ getAmounts: (args)=>UniswapV2.getAmounts({ ...args, exchange: exchange$i }),
+ getPrep: (args)=>UniswapV2.getPrep({ ...args, exchange: exchange$i }),
+ getTransaction: (args)=>UniswapV2.getTransaction({ ...args, exchange: exchange$i }),
})
)
};
@@ -1944,7 +1947,7 @@ let getAccounts = async (base, quote) => {
return accounts
};
-let getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+let getPairsWithPrice$4 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
try {
let accounts = await getAccounts(tokenIn, tokenOut);
if(accounts.length === 0) { accounts = await getAccounts(tokenOut, tokenIn); }
@@ -1971,32 +1974,31 @@ let getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amount
}
};
-let getHighestPrice = (pairs)=>{
+let getHighestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).gt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
-let getLowestPrice = (pairs)=>{
+let getLowestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).lt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
-let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
- const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+let getBestPair$1 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice$4({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
if(!pairs || pairs.length === 0) { return }
let bestPair;
if(amountIn || amountInMax) {
- bestPair = getHighestPrice(pairs);
+ bestPair = getHighestPrice$1(pairs);
} else { // amount out
- bestPair = getLowestPrice(pairs);
+ bestPair = getLowestPrice$1(pairs);
}
-
return bestPair
};
-function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
-const blockchain$1 = Blockchains.solana;
+function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+const blockchain$3 = Blockchains.solana;
// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
//
@@ -2004,64 +2006,64 @@ const blockchain$1 = Blockchains.solana;
// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
// as they are not the same!
//
-let getExchangePath$3 = ({ path }) => {
+let getExchangePath$4 = ({ path }) => {
if(!path) { return }
let exchangePath = path.map((token, index) => {
if (
- token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
- path[index-1] != blockchain$1.wrapped.address
+ token === blockchain$3.currency.address && path[index+1] != blockchain$3.wrapped.address &&
+ path[index-1] != blockchain$3.wrapped.address
) {
- return blockchain$1.wrapped.address
+ return blockchain$3.wrapped.address
} else {
return token
}
});
- if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ if(exchangePath[0] == blockchain$3.currency.address && exchangePath[1] == blockchain$3.wrapped.address) {
exchangePath.splice(0, 1);
- } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ } else if(exchangePath[exchangePath.length-1] == blockchain$3.currency.address && exchangePath[exchangePath.length-2] == blockchain$3.wrapped.address) {
exchangePath.splice(exchangePath.length-1, 1);
}
return exchangePath
};
-let pathExists$4 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+let pathExists$5 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
if(path.length == 1) { return false }
- path = getExchangePath$3({ path });
- if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ path = getExchangePath$4({ path });
+ if((await getPairsWithPrice$4({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
return true
} else {
return false
}
};
-let findPath$4 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+let findPath$5 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
if(
- [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
- [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ [tokenIn, tokenOut].includes(blockchain$3.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$3.wrapped.address)
) { return { path: undefined, exchangePath: undefined } }
let path, stablesIn, stablesOut, stable;
- if (await pathExists$4({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ if (await pathExists$5({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
// direct path
path = [tokenIn, tokenOut];
} else if (
- tokenIn != blockchain$1.wrapped.address &&
- tokenIn != blockchain$1.currency.address &&
- await pathExists$4({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
- tokenOut != blockchain$1.wrapped.address &&
- tokenOut != blockchain$1.currency.address &&
- await pathExists$4({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ tokenIn != blockchain$3.wrapped.address &&
+ tokenIn != blockchain$3.currency.address &&
+ await pathExists$5({ path: [tokenIn, blockchain$3.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$3.wrapped.address &&
+ tokenOut != blockchain$3.currency.address &&
+ await pathExists$5({ path: [tokenOut, blockchain$3.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
) {
// path via blockchain.wrapped.address
- path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ path = [tokenIn, blockchain$3.wrapped.address, tokenOut];
} else if (
- !blockchain$1.stables.usd.includes(tokenIn) &&
- (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
- !blockchain$1.stables.usd.includes(tokenOut) &&
- (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$5({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$5({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
(stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
) {
// path via TOKEN_IN <> STABLE <> TOKEN_OUT
@@ -2070,22 +2072,26 @@ let findPath$4 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, a
// Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
// because that actually reflects how things are routed in reality:
- if(_optionalChain$3([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
- path.splice(1, 0, blockchain$1.wrapped.address);
- } else if(_optionalChain$3([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
- path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ if(_optionalChain$5([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$3.currency.address) {
+ path.splice(1, 0, blockchain$3.wrapped.address);
+ } else if(_optionalChain$5([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$3.currency.address) {
+ path.splice(path.length-1, 0, blockchain$3.wrapped.address);
}
- return { path, exchangePath: getExchangePath$3({ path }) }
+ return { path, exchangePath: getExchangePath$4({ path }) }
};
-let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+let getAmountsOut$1 = async ({ path, amountIn, amountInMax }) => {
let amounts = [ethers.BigNumber.from(amountIn || amountInMax)];
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -2093,15 +2099,19 @@ let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
return amounts
};
-let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+let getAmountsIn$1 = async({ path, amountOut, amountOutMin }) => {
path = path.slice().reverse();
let amounts = [ethers.BigNumber.from(amountOut || amountOutMin)];
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -2109,7 +2119,7 @@ let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
return amounts.slice().reverse()
};
-let getAmounts$4 = async ({
+let getAmounts$5 = async ({
path,
tokenIn,
tokenOut,
@@ -2118,10 +2128,10 @@ let getAmounts$4 = async ({
amountInMax,
amountOutMin
}) => {
- path = getExchangePath$3({ path });
+ path = getExchangePath$4({ path });
let amounts;
if (amountOut) {
- amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOut, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -2129,7 +2139,7 @@ let getAmounts$4 = async ({
amountInMax = amountIn;
}
} else if (amountIn) {
- amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountIn, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -2137,7 +2147,7 @@ let getAmounts$4 = async ({
amountOutMin = amountOut;
}
} else if(amountOutMin) {
- amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOutMin, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -2145,7 +2155,7 @@ let getAmounts$4 = async ({
amountInMax = amountIn;
}
} else if(amountInMax) {
- amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountInMax, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -2162,7 +2172,7 @@ let getAmounts$4 = async ({
}
};
-const blockchain = Blockchains.solana;
+const blockchain$2 = Blockchains.solana;
const SWAP_INSTRUCTION = new BN("14449647541112719096");
const TWO_HOP_SWAP_INSTRUCTION = new BN("16635068063392030915");
@@ -2377,7 +2387,7 @@ const getSwapInstructionData = ({ amount, otherAmountThreshold, sqrtPriceLimit,
return data
};
-const getTransaction$4 = async ({
+const getTransaction$5 = async ({
path,
amountIn,
amountInMax,
@@ -2393,7 +2403,7 @@ const getTransaction$4 = async ({
let transaction = { blockchain: 'solana' };
let instructions = [];
- const exchangePath = getExchangePath$3({ path });
+ const exchangePath = getExchangePath$4({ path });
if(exchangePath.length > 3) { throw 'Orca can only handle fixed paths with a max length of 3 (2 pools)!' }
const tokenIn = exchangePath[0];
const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
@@ -2401,19 +2411,19 @@ const getTransaction$4 = async ({
let pairs;
if(exchangePath.length == 2) {
- pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs = [await getBestPair$1({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
} else {
if(amountInInput || amountInMaxInput) {
- pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
- pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
} else { // originally amountOut
- pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
- pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
}
}
- let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
- let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let startsWrapped = (path[0] === blockchain$2.currency.address && exchangePath[0] === blockchain$2.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain$2.currency.address && exchangePath[exchangePath.length-1] === blockchain$2.wrapped.address);
let wrappedAccount;
const provider = await getProvider('solana');
@@ -2434,7 +2444,7 @@ const getTransaction$4 = async ({
instructions.push(
Token.solana.initializeAccountInstruction({
account: wrappedAccount,
- token: blockchain.wrapped.address,
+ token: blockchain$2.wrapped.address,
owner: account
})
);
@@ -2531,14 +2541,14 @@ const getTransaction$4 = async ({
};
var Orca = {
- findPath: findPath$4,
- pathExists: pathExists$4,
- getAmounts: getAmounts$4,
- getTransaction: getTransaction$4,
+ findPath: findPath$5,
+ pathExists: pathExists$5,
+ getAmounts: getAmounts$5,
+ getTransaction: getTransaction$5,
WHIRLPOOL_LAYOUT,
};
-const exchange$g = {
+const exchange$h = {
name: 'orca',
label: 'Orca',
@@ -2559,16 +2569,815 @@ const exchange$g = {
var orca = (scope)=>{
+ return new Exchange(
+
+ Object.assign(exchange$h, {
+ scope,
+
+ findPath: (args)=>Orca.findPath({ ...args, exchange: exchange$h }),
+ pathExists: (args)=>Orca.pathExists({ ...args, exchange: exchange$h }),
+ getAmounts: (args)=>Orca.getAmounts({ ...args, exchange: exchange$h }),
+ getPrep: (args)=>{},
+ getTransaction: (args)=>Orca.getTransaction({ ...args, exchange: exchange$h }),
+ })
+ )
+};
+
+// OpenBook Market
+const MARKET_LAYOUT = struct([
+ blob(5),
+ blob(8), // accountFlagsLayout('accountFlags'),
+ publicKey('ownAddress'),
+ u64$1('vaultSignerNonce'),
+ publicKey('baseMint'),
+ publicKey('quoteMint'),
+ publicKey('baseVault'),
+ u64$1('baseDepositsTotal'),
+ u64$1('baseFeesAccrued'),
+ publicKey('quoteVault'),
+ u64$1('quoteDepositsTotal'),
+ u64$1('quoteFeesAccrued'),
+ u64$1('quoteDustThreshold'),
+ publicKey('requestQueue'),
+ publicKey('eventQueue'),
+ publicKey('bids'),
+ publicKey('asks'),
+ u64$1('baseLotSize'),
+ u64$1('quoteLotSize'),
+ u64$1('feeRateBps'),
+ u64$1('referrerRebatesAccrued'),
+ blob(7),
+]);
+
+// AMM 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
+const AMM_LAYOUT = struct([
+ u64$1('status'),
+ u64$1('nonce'),
+ u64$1('maxOrder'),
+ u64$1('depth'),
+ u64$1('baseDecimal'),
+ u64$1('quoteDecimal'),
+ u64$1('state'),
+ u64$1('resetFlag'),
+ u64$1('minSize'),
+ u64$1('volMaxCutRatio'),
+ u64$1('amountWaveRatio'),
+ u64$1('baseLotSize'),
+ u64$1('quoteLotSize'),
+ u64$1('minPriceMultiplier'),
+ u64$1('maxPriceMultiplier'),
+ u64$1('systemDecimalValue'),
+ u64$1('minSeparateNumerator'),
+ u64$1('minSeparateDenominator'),
+ u64$1('tradeFeeNumerator'),
+ u64$1('tradeFeeDenominator'),
+ u64$1('pnlNumerator'),
+ u64$1('pnlDenominator'),
+ u64$1('swapFeeNumerator'),
+ u64$1('swapFeeDenominator'),
+ u64$1('baseNeedTakePnl'),
+ u64$1('quoteNeedTakePnl'),
+ u64$1('quoteTotalPnl'),
+ u64$1('baseTotalPnl'),
+ u64$1('poolOpenTime'),
+ u64$1('punishPcAmount'),
+ u64$1('punishCoinAmount'),
+ u64$1('orderbookToInitTime'),
+ u128('swapBaseInAmount'),
+ u128('swapQuoteOutAmount'),
+ u64$1('swapBase2QuoteFee'),
+ u128('swapQuoteInAmount'),
+ u128('swapBaseOutAmount'),
+ u64$1('swapQuote2BaseFee'),
+ // amm vault
+ publicKey('baseVault'),
+ publicKey('quoteVault'),
+ // mint
+ publicKey('baseMint'),
+ publicKey('quoteMint'),
+ publicKey('lpMint'),
+ // market
+ publicKey('openOrders'),
+ publicKey('marketId'),
+ publicKey('marketProgramId'),
+ publicKey('targetOrders'),
+ publicKey('withdrawQueue'),
+ publicKey('lpVault'),
+ publicKey('owner'),
+ // true circulating supply without lock up
+ u64$1('lpReserve'),
+ seq(u64$1(), 3, 'padding'),
+]);
+
+// CP_AMM CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
+const CPAMM_LAYOUT = struct([
+ blob(8),
+ publicKey("configId"),
+ publicKey("poolCreator"),
+ publicKey("vaultA"),
+ publicKey("vaultB"),
+ publicKey("mintLp"),
+ publicKey("mintA"),
+ publicKey("mintB"),
+ publicKey("mintProgramA"),
+ publicKey("mintProgramB"),
+ publicKey("observationId"),
+ u8("bump"),
+ u8("status"),
+ u8("lpDecimals"),
+ u8("mintDecimalA"),
+ u8("mintDecimalB"),
+ u64$1("lpAmount"),
+ u64$1("protocolFeesMintA"),
+ u64$1("protocolFeesMintB"),
+ u64$1("fundFeesMintA"),
+ u64$1("fundFeesMintB"),
+ u64$1("openTime"),
+ seq(u64$1(), 32),
+]);
+
+// CLMM
+
+const RewardInfo = struct([
+ u8("rewardState"),
+ u64$1("openTime"),
+ u64$1("endTime"),
+ u64$1("lastUpdateTime"),
+ u128("emissionsPerSecondX64"),
+ u64$1("rewardTotalEmissioned"),
+ u64$1("rewardClaimed"),
+ publicKey("tokenMint"),
+ publicKey("tokenVault"),
+ publicKey("creator"),
+ u128("rewardGrowthGlobalX64"),
+]);
+
+const CLMM_LAYOUT = struct([
+ blob(8),
+ u8("bump"),
+ publicKey("ammConfig"),
+ publicKey("creator"),
+ publicKey("mintA"),
+ publicKey("mintB"),
+ publicKey("vaultA"),
+ publicKey("vaultB"),
+ publicKey("observationId"),
+ u8("mintDecimalsA"),
+ u8("mintDecimalsB"),
+ u16("tickSpacing"),
+ u128("liquidity"),
+ u128("sqrtPriceX64"),
+ i32("tickCurrent"),
+ u32(),
+ u128("feeGrowthGlobalX64A"),
+ u128("feeGrowthGlobalX64B"),
+ u64$1("protocolFeesTokenA"),
+ u64$1("protocolFeesTokenB"),
+ u128("swapInAmountTokenA"),
+ u128("swapOutAmountTokenB"),
+ u128("swapInAmountTokenB"),
+ u128("swapOutAmountTokenA"),
+ u8("status"),
+ seq(u8(), 7, ""),
+ seq(RewardInfo, 3, "rewardInfos"),
+ seq(u64$1(), 16, "tickArrayBitmap"),
+ u64$1("totalFeesTokenA"),
+ u64$1("totalFeesClaimedTokenA"),
+ u64$1("totalFeesTokenB"),
+ u64$1("totalFeesClaimedTokenB"),
+ u64$1("fundFeesTokenA"),
+ u64$1("fundFeesTokenB"),
+ u64$1("startTime"),
+ seq(u64$1(), 15 * 4 - 3, "padding"),
+]);
+
+function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+
+const LIQUIDITY_FEES_NUMERATOR = new BN(25);
+const LIQUIDITY_FEES_DENOMINATOR = new BN(10000);
+
+const BNDivCeil = (bn1, bn2)=> {
+ const { div, mod } = bn1.divmod(bn2);
+
+ if (mod.gt(new BN(0))) {
+ return div.add(new BN(1))
+ } else {
+ return div
+ }
+};
+
+const getPairs = (base, quote)=>{
+ return request(`solana://675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8/getProgramAccounts`, {
+ params: { filters: [
+ { dataSize: AMM_LAYOUT.span },
+ { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6 (Swap)
+ { memcmp: { offset: 400, bytes: base }},
+ { memcmp: { offset: 432, bytes: quote }},
+ ]},
+ api: AMM_LAYOUT,
+ cache: 86400, // 24h,
+ cacheKey: ['raydium', base.toString(), quote.toString()].join('-')
+ })
+};
+
+const getPairsWithPrice$3 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ let accounts = await getPairs(tokenIn, tokenOut);
+
+ if(accounts.length == 0) {
+ accounts = await getPairs(tokenOut, tokenIn);
+ }
+
+ const pairs = await Promise.all(accounts.map(async(account)=>{
+
+ const baseMint = account.data.baseMint.toString();
+ const quoteMint = account.data.quoteMint.toString();
+
+ const balances = await Promise.all([
+ request(`solana://${account.data.baseVault.toString()}/getTokenAccountBalance`, { cache: 5 }),
+ request(`solana://${account.data.quoteVault.toString()}/getTokenAccountBalance`, { cache: 5 })
+ ]);
+ const baseReserve = (_optionalChain$4([balances, 'access', _ => _[0], 'optionalAccess', _2 => _2.value, 'optionalAccess', _3 => _3.amount]) ? new BN(_optionalChain$4([balances, 'access', _4 => _4[0], 'optionalAccess', _5 => _5.value, 'optionalAccess', _6 => _6.amount])) : new BN(0)).sub(account.data.baseNeedTakePnl);
+ const quoteReserve = (_optionalChain$4([balances, 'access', _7 => _7[1], 'optionalAccess', _8 => _8.value, 'optionalAccess', _9 => _9.amount]) ? new BN(_optionalChain$4([balances, 'access', _10 => _10[1], 'optionalAccess', _11 => _11.value, 'optionalAccess', _12 => _12.amount])) : new BN(0)).sub(account.data.quoteNeedTakePnl);
+
+ if(baseMint === Blockchains.solana.wrapped.address) {
+ if(baseReserve.lt(new BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (quoteMint === Blockchains.solana.wrapped.address) {
+ if(quoteReserve.lt(new BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (Blockchains.solana.stables.usd.includes(baseMint)) {
+ if((parseFloat(baseReserve.toString()) / 10 ** account.data.baseDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ } else if (Blockchains.solana.stables.usd.includes(quoteMint)) {
+ if((parseFloat(quoteReserve.toString()) / 10 ** account.data.quoteDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ }
+
+ const reserves = [baseReserve, quoteReserve];
+
+ if(tokenOut === baseMint) {
+ reserves.reverse();
+ }
+
+ const [reserveIn, reserveOut] = reserves;
+
+ let price;
+ if(amountOut || amountOutMin) { // compute amountIn
+
+ new BN(0);
+ let amountOutRaw = new BN((amountOut || amountOutMin).toString());
+
+ if (amountOutRaw.gt(reserveOut)) {
+ amountOutRaw = reserveOut.sub(new BN(1));
+ }
+
+ const denominator = reserveOut.sub(amountOutRaw);
+ const amountInWithoutFee = reserveIn.mul(amountOutRaw).div(denominator);
+
+ price = amountInWithoutFee
+ .mul(LIQUIDITY_FEES_DENOMINATOR)
+ .div(LIQUIDITY_FEES_DENOMINATOR.sub(LIQUIDITY_FEES_NUMERATOR))
+ .toString();
+
+ } else { // compute amountOut
+
+ new BN(0);
+ const amountInRaw = new BN((amountIn || amountInMin).toString());
+ const feeRaw = BNDivCeil(amountInRaw.mul(LIQUIDITY_FEES_NUMERATOR), LIQUIDITY_FEES_DENOMINATOR);
+
+ const amountInWithFee = amountInRaw.sub(feeRaw);
+ const denominator = reserveIn.add(amountInWithFee);
+
+ price = reserveOut.mul(amountInWithFee).div(denominator).toString();
+ }
+
+ return {
+ publicKey: account.pubkey.toString(),
+ baseMint,
+ quoteMint,
+ price,
+ data: account.data
+ }
+
+ }));
+
+ return pairs.filter(Boolean)
+};
+
+const getPairsWithPrice$2 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+};
+
+const getPairsWithPrice$1 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+};
+
+const getParisWithPriceForAllTypes = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ return Promise.all([
+ getPairsWithPrice$3({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$2({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$1({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ ]).then((pairsAMM, pairsCPAMM, pairsCLMNN)=>{
+ return [
+ (pairsAMM || []).filter(Boolean).flat(),
+ (pairsCPAMM || []).filter(Boolean).flat(),
+ (pairsCLMNN || []).filter(Boolean).flat()
+ ].flat()
+ })
+};
+
+const getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ try {
+ return await getParisWithPriceForAllTypes({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })
+ } catch (e) {
+ return []
+ }
+};
+
+let getHighestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).gt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+};
+
+let getLowestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).lt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+};
+
+let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+
+ if(!pairs || pairs.length === 0) { return }
+
+ let bestPair;
+
+ if(amountIn || amountInMax) {
+ bestPair = getHighestPrice(pairs);
+ } else { // amount out
+ bestPair = getLowestPrice(pairs);
+ }
+
+ return bestPair
+};
+
+function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+const blockchain$1 = Blockchains.solana;
+
+// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
+//
+// We keep 11111111111111111111111111111111 internally
+// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
+// as they are not the same!
+//
+let getExchangePath$3 = ({ path }) => {
+ if(!path) { return }
+ let exchangePath = path.map((token, index) => {
+ if (
+ token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
+ path[index-1] != blockchain$1.wrapped.address
+ ) {
+ return blockchain$1.wrapped.address
+ } else {
+ return token
+ }
+ });
+
+ if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ exchangePath.splice(0, 1);
+ } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ exchangePath.splice(exchangePath.length-1, 1);
+ }
+
+ return exchangePath
+};
+
+let pathExists$4 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ if(path.length == 1) { return false }
+ path = getExchangePath$3({ path });
+ if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ return true
+ } else {
+ return false
+ }
+};
+
+let findPath$4 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ if(
+ [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ ) { return { path: undefined, exchangePath: undefined } }
+
+ let path, stablesIn, stablesOut, stable;
+
+ if (await pathExists$4({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ // direct path
+ path = [tokenIn, tokenOut];
+ } else if (
+ tokenIn != blockchain$1.wrapped.address &&
+ tokenIn != blockchain$1.currency.address &&
+ await pathExists$4({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$1.wrapped.address &&
+ tokenOut != blockchain$1.currency.address &&
+ await pathExists$4({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ ) {
+ // path via blockchain.wrapped.address
+ path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ } else if (
+ !blockchain$1.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$1.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ (stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
+ ) {
+ // path via TOKEN_IN <> STABLE <> TOKEN_OUT
+ path = [tokenIn, stable, tokenOut];
+ }
+
+ // Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
+ // because that actually reflects how things are routed in reality:
+ if(_optionalChain$3([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
+ path.splice(1, 0, blockchain$1.wrapped.address);
+ } else if(_optionalChain$3([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
+ path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ }
+ return { path, exchangePath: getExchangePath$3({ path }) }
+};
+
+let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+
+ let amounts = [ethers.BigNumber.from(amountIn || amountInMax)];
+
+ let bestPair = await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts
+};
+
+let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+
+ path = path.slice().reverse();
+ let amounts = [ethers.BigNumber.from(amountOut || amountOutMin)];
+
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts.slice().reverse()
+};
+
+let getAmounts$4 = async ({
+ path,
+ tokenIn,
+ tokenOut,
+ amountOut,
+ amountIn,
+ amountInMax,
+ amountOutMin
+}) => {
+ path = getExchangePath$3({ path });
+ let amounts;
+ if (amountOut) {
+ amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if (amountIn) {
+ amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ } else if(amountOutMin) {
+ amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if(amountInMax) {
+ amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ }
+ return {
+ amountOut: (amountOut || amountOutMin),
+ amountIn: (amountIn || amountInMax),
+ amountInMax: (amountInMax || amountIn),
+ amountOutMin: (amountOutMin || amountOut),
+ amounts
+ }
+};
+
+const blockchain = Blockchains.solana;
+
+const getTransaction$4 = async({
+ path,
+ amountIn,
+ amountInMax,
+ amountOut,
+ amountOutMin,
+ amounts,
+ amountInInput,
+ amountOutInput,
+ amountInMaxInput,
+ amountOutMinInput,
+ account
+})=>{
+ let transaction = { blockchain: 'solana' };
+ let instructions = [];
+
+ const exchangePath = getExchangePath$3({ path });
+ if(exchangePath.length > 3) { throw 'Raydium can only handle fixed paths with a max length of 3 (2 pools)!' }
+ const tokenIn = exchangePath[0];
+ const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
+ const tokenOut = exchangePath[exchangePath.length-1];
+
+ let pairs;
+ if(exchangePath.length == 2) {
+ pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ } else {
+ if(amountInInput || amountInMaxInput) {
+ pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ } else { // originally amountOut
+ pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ }
+ }
+
+ let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let wrappedAccount;
+ const provider = await getProvider('solana');
+
+ if(startsWrapped || endsUnwrapped) {
+ const rent = await provider.getMinimumBalanceForRentExemption(Token.solana.TOKEN_LAYOUT.span);
+ const keypair = Keypair.generate();
+ wrappedAccount = keypair.publicKey.toString();
+ const lamports = startsWrapped ? new BN(amountIn.toString()).add(new BN(rent)) : new BN(rent);
+ let createAccountInstruction = SystemProgram.createAccount({
+ fromPubkey: new PublicKey(account),
+ newAccountPubkey: new PublicKey(wrappedAccount),
+ programId: new PublicKey(Token.solana.TOKEN_PROGRAM),
+ space: Token.solana.TOKEN_LAYOUT.span,
+ lamports
+ });
+ createAccountInstruction.signers = [keypair];
+ instructions.push(createAccountInstruction);
+ instructions.push(
+ Token.solana.initializeAccountInstruction({
+ account: wrappedAccount,
+ token: blockchain.wrapped.address,
+ owner: account
+ })
+ );
+ }
+
+ if(pairs.length === 1) { // single hop
+ const tokenAccountIn = startsWrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenIn }));
+ const tokenAccountOut = endsUnwrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenOut }));
+ const pool = pairs[0];
+ await request(`solana://${pool.data.marketId}/getAccountInfo`, { api: MARKET_LAYOUT });
+
+ let LAYOUT, data;
+ LAYOUT = struct([
+ u8('instruction'),
+ u64$1('amountIn'),
+ u64$1('minAmountOut')
+ ]);
+ data = Buffer.alloc(LAYOUT.span);
+ LAYOUT.encode(
+ {
+ instruction: 9,
+ amountIn: new BN((amountIn || amountInMax).toString()),
+ minAmountOut: new BN((amountOutMin || amountOut).toString()),
+ },
+ data,
+ );
+
+ // if(!endsUnwrapped) {
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenOut, account: tokenAccountOut })
+ // }
+
+ // let keys = [
+ // // token_program
+ // { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // // amm
+ // { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // // amm authority
+ // { pubkey: await getAssociatedAuthority(new PublicKey(pool.publicKey)), isWritable: false, isSigner: false },
+ // // amm openOrders
+ // { pubkey: new PublicKey(pool.data.openOrders), isWritable: true, isSigner: false },
+ // // amm baseVault
+ // { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // // amm quoteVault
+ // { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // // openbook marketProgramId
+ // { pubkey: new PublicKey(pool.data.marketProgramId), isWritable: false, isSigner: false },
+ // // openbook marketId
+ // { pubkey: new PublicKey(pool.data.marketId), isWritable: true, isSigner: false },
+ // // openbook marketBids
+ // { pubkey: market.bids, isWritable: true, isSigner: false },
+ // // openbook marketAsks
+ // { pubkey: market.asks, isWritable: true, isSigner: false },
+ // // openbook eventQueue
+ // { pubkey: market.eventQueue, isWritable: true, isSigner: false },
+ // // openbook baseVault
+ // { pubkey: market.baseVault, isWritable: true, isSigner: false },
+ // // openbook quoteVault
+ // { pubkey: market.quoteVault, isWritable: true, isSigner: false },
+ // // openbook marketAuthority
+ // { pubkey: await getAssociatedMarketAuthority(pool.data.marketProgramId, pool.data.marketId), isWritable: false, isSigner: false },
+ // // user tokenAccountIn
+ // { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // // user tokenAccountOut
+ // { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // // user owner
+ // { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ // ]
+
+ let keys = [
+ // token_program
+ { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // amm
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm authority
+ { pubkey: new PublicKey('5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1'), isWritable: false, isSigner: false },
+ // amm openOrders
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm baseVault
+ { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // amm quoteVault
+ { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // openbook marketProgramId
+ { pubkey: new PublicKey(pool.publicKey), isWritable: false, isSigner: false },
+ // openbook marketId
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketBids
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAsks
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook eventQueue
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook baseVault
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook quoteVault
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAuthority
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // user tokenAccountIn
+ { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // user tokenAccountOut
+ { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // user owner
+ { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ ];
+
+ console.log('keys', JSON.stringify(keys));
+
+ instructions.push(
+ new TransactionInstruction({
+ programId: new PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'),
+ keys,
+ data,
+ })
+ );
+ } else if (pairs.length === 2) ;
+
+ if(startsWrapped || endsUnwrapped) {
+ instructions.push(
+ Token.solana.closeAccountInstruction({
+ account: wrappedAccount,
+ owner: account
+ })
+ );
+ }
+
+ // await debug(instructions, provider)
+
+ transaction.instructions = instructions;
+ return transaction
+};
+
+var Raydium = {
+ findPath: findPath$4,
+ pathExists: pathExists$4,
+ getAmounts: getAmounts$4,
+ getTransaction: getTransaction$4,
+ AMM_LAYOUT,
+ CPAMM_LAYOUT,
+ CLMM_LAYOUT,
+ MARKET_LAYOUT,
+};
+
+// // AMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_amm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_amm.api.span },
+// { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6
+// { memcmp: { offset: 400, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 432, bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_amm.api,
+// })
+// console.log(accounts)
+
+
+// // CPAMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_cpamm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_cpamm.api.span },
+// { memcmp: { offset: 168, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 200, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_cpamm.api,
+// })
+// console.log(accounts)
+
+
+// // CLMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_clmm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_clmm.api.span },
+// { memcmp: { offset: 73, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 105, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_clmm.api,
+// })
+// console.log(accounts)
+
+const exchange$g = {
+
+ name: 'raydium',
+ label: 'Raydium',
+ logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjMzIiB2aWV3Qm94PSIwIDAgMjkgMzMiIHdpZHRoPSIyOSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjI4LjMxNjgiIHgyPSItMS43MzMzNiIgeTE9IjguMTkxNjIiIHkyPSIyMC4yMDg2Ij48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNjMjAwZmIiLz48c3RvcCBvZmZzZXQ9Ii40ODk2NTgiIHN0b3AtY29sb3I9IiMzNzcyZmYiLz48c3RvcCBvZmZzZXQ9Ii40ODk3NTgiIHN0b3AtY29sb3I9IiMzNzczZmUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM1YWM0YmUiLz48L2xpbmVhckdyYWRpZW50PjxnIGZpbGw9InVybCgjYSkiPjxwYXRoIGQ9Im0yNi44NjI1IDEyLjI4MXYxMS40MTA0bC0xMi42OTE2IDcuMzI2MS0xMi42OTg1OS03LjMyNjF2LTE0LjY1OTM3bDEyLjY5ODU5LTcuMzMzMjIgOS43NTQxIDUuNjM0NDEgMS40NzIzLS44NDk0MS0xMS4yMjY0LTYuNDgzODEtMTQuMTcwOSA4LjE4MjYydjE2LjM1ODE4bDE0LjE3MDkgOC4xODI2IDE0LjE3MS04LjE4MjZ2LTEzLjEwOTJ6Ii8+PHBhdGggZD0ibTEwLjYxNzYgMjMuNjk4NWgtMi4xMjM1M3YtNy4xMjA5aDcuMDc4NDNjLjY2OTctLjAwNzQgMS4zMDk1LS4yNzgyIDEuNzgxMS0uNzUzOC40NzE2LS40NzU1LjczNy0xLjExNzYuNzM4OC0xLjc4NzQuMDAzOC0uMzMxMS0uMDYwMS0uNjU5Ni0uMTg3OS0uOTY1MS0uMTI3OS0uMzA1Ni0uMzE2OC0uNTgxNy0uNTU1NC0uODExNS0uMjMwOC0uMjM3Mi0uNTA3MS0uNDI1My0uODEyNC0uNTUzLS4zMDUzLS4xMjc4LS42MzMzLS4xOTI1LS45NjQyLS4xOTAzaC03LjA3ODQzdi0yLjE2NTk1aDcuMDg1NDNjMS4yNDA1LjAwNzQzIDIuNDI4MS41MDM1MSAzLjMwNTMgMS4zODA2NS44NzcxLjg3NzIgMS4zNzMyIDIuMDY0OCAxLjM4MDYgMy4zMDUyLjAwNzYuOTQ5Ni0uMjgxOSAxLjg3NzctLjgyODEgMi42NTQ0LS41MDI3Ljc0MzItMS4yMTExIDEuMzIzNy0yLjAzODYgMS42NzA1LS44MTk0LjI1OTktMS42NzQ1LjM4ODktMi41MzQxLjM4MjNoLTQuMjQ3eiIvPjxwYXRoIGQ9Im0yMC4yMTU5IDIzLjUyMTVoLTIuNDc3NWwtMS45MTExLTMuMzMzOWMuNzU2MS0uMDQ2MyAxLjUwMTktLjE5ODggMi4yMTU1LS40NTN6Ii8+PHBhdGggZD0ibTI1LjM4MzEgOS45MDk3NSAxLjQ2NTIuODE0MDUgMS40NjUzLS44MTQwNXYtMS43MjAwNWwtMS40NjUzLS44NDk0MS0xLjQ2NTIuODQ5NDF6Ii8+PC9nPjwvc3ZnPg==',
+ protocol: 'raydium',
+
+ slippage: true,
+
+ blockchains: ['solana'],
+
+ solana: {
+
+ router_amm: {
+ address: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
+ api: Raydium.AMM_LAYOUT,
+ },
+
+ router_cpamm: {
+ address: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C',
+ api: Raydium.CPAMM_LAYOUT
+ },
+
+ router_clmm: {
+ address: 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK',
+ api: Raydium.CLMM_LAYOUT
+ },
+ }
+};
+
+var raydium = (scope)=>{
+
return new Exchange(
Object.assign(exchange$g, {
scope,
- findPath: (args)=>Orca.findPath({ ...args, exchange: exchange$g }),
- pathExists: (args)=>Orca.pathExists({ ...args, exchange: exchange$g }),
- getAmounts: (args)=>Orca.getAmounts({ ...args, exchange: exchange$g }),
+ findPath: (args)=>Raydium.findPath({ ...args, exchange: exchange$g }),
+ pathExists: (args)=>Raydium.pathExists({ ...args, exchange: exchange$g }),
+ getAmounts: (args)=>Raydium.getAmounts({ ...args, exchange: exchange$g }),
getPrep: (args)=>{},
- getTransaction: (args)=>Orca.getTransaction({ ...args, exchange: exchange$g }),
+ getTransaction: (args)=>Raydium.getTransaction({ ...args, exchange: exchange$g }),
})
)
};
@@ -4812,6 +5621,7 @@ var wxdai = (scope)=>{
const exchanges = [
orca(),
+ raydium(),
uniswap_v3(),
pancakeswap_v3(),
uniswap_v2(),
@@ -4858,6 +5668,7 @@ exchanges.polygon.forEach((exchange)=>{ exchanges.polygon[exchange.name] = excha
exchanges.solana = [
orca('solana'),
+ raydium('solana'),
];
exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchange; });
diff --git a/dist/esm/index.solana.js b/dist/esm/index.solana.js
index 30c1578..b90610d 100644
--- a/dist/esm/index.solana.js
+++ b/dist/esm/index.solana.js
@@ -2,10 +2,10 @@ import Token from '@depay/web3-tokens-solana';
import { request, getProvider } from '@depay/web3-client-solana';
import { ethers } from 'ethers';
import Blockchains from '@depay/web3-blockchains';
-import { BN, struct, publicKey, u128, u64 as u64$1, seq, u8, u16, i32, bool, i128, PublicKey, Buffer, Keypair, SystemProgram, TransactionInstruction } from '@depay/solana-web3.js';
+import { BN, struct, publicKey, u128, u64 as u64$1, seq, u8, u16, i32, bool, i128, PublicKey, Buffer, Keypair, SystemProgram, TransactionInstruction, blob, u32 } from '@depay/solana-web3.js';
import Decimal from 'decimal.js';
-function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
+function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
constructor({
blockchain,
tokenIn,
@@ -31,10 +31,10 @@ function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[
this.decimalsOut = decimalsOut;
this.path = path;
this.pools = pools;
- this.amountIn = _optionalChain$1([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
- this.amountOutMin = _optionalChain$1([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
- this.amountOut = _optionalChain$1([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
- this.amountInMax = _optionalChain$1([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
+ this.amountIn = _optionalChain$3([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
+ this.amountOutMin = _optionalChain$3([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
+ this.amountOut = _optionalChain$3([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
+ this.amountInMax = _optionalChain$3([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
this.exchange = exchange;
this.getPrep = getPrep;
this.getTransaction = getTransaction;
@@ -308,7 +308,10 @@ const route$1 = ({
let amounts; // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch (e) { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
@@ -1587,7 +1590,7 @@ let getAccounts = async (base, quote) => {
return accounts
};
-let getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+let getPairsWithPrice$4 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
try {
let accounts = await getAccounts(tokenIn, tokenOut);
if(accounts.length === 0) { accounts = await getAccounts(tokenOut, tokenIn); }
@@ -1614,32 +1617,31 @@ let getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amount
}
};
-let getHighestPrice = (pairs)=>{
+let getHighestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).gt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
-let getLowestPrice = (pairs)=>{
+let getLowestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).lt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
-let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
- const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+let getBestPair$1 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice$4({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
if(!pairs || pairs.length === 0) { return }
let bestPair;
if(amountIn || amountInMax) {
- bestPair = getHighestPrice(pairs);
+ bestPair = getHighestPrice$1(pairs);
} else { // amount out
- bestPair = getLowestPrice(pairs);
+ bestPair = getLowestPrice$1(pairs);
}
-
return bestPair
};
-function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
-const blockchain$1 = Blockchains.solana;
+function _optionalChain$2(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+const blockchain$3 = Blockchains.solana;
// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
//
@@ -1647,64 +1649,64 @@ const blockchain$1 = Blockchains.solana;
// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
// as they are not the same!
//
-let getExchangePath = ({ path }) => {
+let getExchangePath$1 = ({ path }) => {
if(!path) { return }
let exchangePath = path.map((token, index) => {
if (
- token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
- path[index-1] != blockchain$1.wrapped.address
+ token === blockchain$3.currency.address && path[index+1] != blockchain$3.wrapped.address &&
+ path[index-1] != blockchain$3.wrapped.address
) {
- return blockchain$1.wrapped.address
+ return blockchain$3.wrapped.address
} else {
return token
}
});
- if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ if(exchangePath[0] == blockchain$3.currency.address && exchangePath[1] == blockchain$3.wrapped.address) {
exchangePath.splice(0, 1);
- } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ } else if(exchangePath[exchangePath.length-1] == blockchain$3.currency.address && exchangePath[exchangePath.length-2] == blockchain$3.wrapped.address) {
exchangePath.splice(exchangePath.length-1, 1);
}
return exchangePath
};
-let pathExists = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+let pathExists$1 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
if(path.length == 1) { return false }
- path = getExchangePath({ path });
- if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ path = getExchangePath$1({ path });
+ if((await getPairsWithPrice$4({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
return true
} else {
return false
}
};
-let findPath = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+let findPath$1 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
if(
- [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
- [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ [tokenIn, tokenOut].includes(blockchain$3.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$3.wrapped.address)
) { return { path: undefined, exchangePath: undefined } }
let path, stablesIn, stablesOut, stable;
- if (await pathExists({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ if (await pathExists$1({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
// direct path
path = [tokenIn, tokenOut];
} else if (
- tokenIn != blockchain$1.wrapped.address &&
- tokenIn != blockchain$1.currency.address &&
- await pathExists({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
- tokenOut != blockchain$1.wrapped.address &&
- tokenOut != blockchain$1.currency.address &&
- await pathExists({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ tokenIn != blockchain$3.wrapped.address &&
+ tokenIn != blockchain$3.currency.address &&
+ await pathExists$1({ path: [tokenIn, blockchain$3.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$3.wrapped.address &&
+ tokenOut != blockchain$3.currency.address &&
+ await pathExists$1({ path: [tokenOut, blockchain$3.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
) {
// path via blockchain.wrapped.address
- path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ path = [tokenIn, blockchain$3.wrapped.address, tokenOut];
} else if (
- !blockchain$1.stables.usd.includes(tokenIn) &&
- (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
- !blockchain$1.stables.usd.includes(tokenOut) &&
- (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$1({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$1({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
(stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
) {
// path via TOKEN_IN <> STABLE <> TOKEN_OUT
@@ -1713,22 +1715,26 @@ let findPath = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amo
// Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
// because that actually reflects how things are routed in reality:
- if(_optionalChain([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
- path.splice(1, 0, blockchain$1.wrapped.address);
- } else if(_optionalChain([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
- path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ if(_optionalChain$2([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$3.currency.address) {
+ path.splice(1, 0, blockchain$3.wrapped.address);
+ } else if(_optionalChain$2([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$3.currency.address) {
+ path.splice(path.length-1, 0, blockchain$3.wrapped.address);
}
- return { path, exchangePath: getExchangePath({ path }) }
+ return { path, exchangePath: getExchangePath$1({ path }) }
};
-let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+let getAmountsOut$1 = async ({ path, amountIn, amountInMax }) => {
let amounts = [ethers.BigNumber.from(amountIn || amountInMax)];
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -1736,15 +1742,19 @@ let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
return amounts
};
-let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+let getAmountsIn$1 = async({ path, amountOut, amountOutMin }) => {
path = path.slice().reverse();
let amounts = [ethers.BigNumber.from(amountOut || amountOutMin)];
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -1752,7 +1762,7 @@ let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
return amounts.slice().reverse()
};
-let getAmounts = async ({
+let getAmounts$1 = async ({
path,
tokenIn,
tokenOut,
@@ -1761,10 +1771,10 @@ let getAmounts = async ({
amountInMax,
amountOutMin
}) => {
- path = getExchangePath({ path });
+ path = getExchangePath$1({ path });
let amounts;
if (amountOut) {
- amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOut, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -1772,7 +1782,7 @@ let getAmounts = async ({
amountInMax = amountIn;
}
} else if (amountIn) {
- amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountIn, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -1780,7 +1790,7 @@ let getAmounts = async ({
amountOutMin = amountOut;
}
} else if(amountOutMin) {
- amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOutMin, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -1788,7 +1798,7 @@ let getAmounts = async ({
amountInMax = amountIn;
}
} else if(amountInMax) {
- amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountInMax, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -1805,7 +1815,7 @@ let getAmounts = async ({
}
};
-const blockchain = Blockchains.solana;
+const blockchain$2 = Blockchains.solana;
const SWAP_INSTRUCTION = new BN("14449647541112719096");
const TWO_HOP_SWAP_INSTRUCTION = new BN("16635068063392030915");
@@ -2020,7 +2030,7 @@ const getSwapInstructionData = ({ amount, otherAmountThreshold, sqrtPriceLimit,
return data
};
-const getTransaction = async ({
+const getTransaction$1 = async ({
path,
amountIn,
amountInMax,
@@ -2036,7 +2046,7 @@ const getTransaction = async ({
let transaction = { blockchain: 'solana' };
let instructions = [];
- const exchangePath = getExchangePath({ path });
+ const exchangePath = getExchangePath$1({ path });
if(exchangePath.length > 3) { throw 'Orca can only handle fixed paths with a max length of 3 (2 pools)!' }
const tokenIn = exchangePath[0];
const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
@@ -2044,19 +2054,19 @@ const getTransaction = async ({
let pairs;
if(exchangePath.length == 2) {
- pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs = [await getBestPair$1({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
} else {
if(amountInInput || amountInMaxInput) {
- pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
- pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
} else { // originally amountOut
- pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
- pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
}
}
- let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
- let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let startsWrapped = (path[0] === blockchain$2.currency.address && exchangePath[0] === blockchain$2.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain$2.currency.address && exchangePath[exchangePath.length-1] === blockchain$2.wrapped.address);
let wrappedAccount;
const provider = await getProvider('solana');
@@ -2077,7 +2087,7 @@ const getTransaction = async ({
instructions.push(
Token.solana.initializeAccountInstruction({
account: wrappedAccount,
- token: blockchain.wrapped.address,
+ token: blockchain$2.wrapped.address,
owner: account
})
);
@@ -2174,14 +2184,14 @@ const getTransaction = async ({
};
var Orca = {
- findPath,
- pathExists,
- getAmounts,
- getTransaction,
+ findPath: findPath$1,
+ pathExists: pathExists$1,
+ getAmounts: getAmounts$1,
+ getTransaction: getTransaction$1,
WHIRLPOOL_LAYOUT,
};
-const exchange = {
+const exchange$1 = {
name: 'orca',
label: 'Orca',
@@ -2202,22 +2212,822 @@ const exchange = {
var orca = (scope)=>{
+ return new Exchange(
+
+ Object.assign(exchange$1, {
+ scope,
+
+ findPath: (args)=>Orca.findPath({ ...args, exchange: exchange$1 }),
+ pathExists: (args)=>Orca.pathExists({ ...args, exchange: exchange$1 }),
+ getAmounts: (args)=>Orca.getAmounts({ ...args, exchange: exchange$1 }),
+ getPrep: (args)=>{},
+ getTransaction: (args)=>Orca.getTransaction({ ...args, exchange: exchange$1 }),
+ })
+ )
+};
+
+// OpenBook Market
+const MARKET_LAYOUT = struct([
+ blob(5),
+ blob(8), // accountFlagsLayout('accountFlags'),
+ publicKey('ownAddress'),
+ u64$1('vaultSignerNonce'),
+ publicKey('baseMint'),
+ publicKey('quoteMint'),
+ publicKey('baseVault'),
+ u64$1('baseDepositsTotal'),
+ u64$1('baseFeesAccrued'),
+ publicKey('quoteVault'),
+ u64$1('quoteDepositsTotal'),
+ u64$1('quoteFeesAccrued'),
+ u64$1('quoteDustThreshold'),
+ publicKey('requestQueue'),
+ publicKey('eventQueue'),
+ publicKey('bids'),
+ publicKey('asks'),
+ u64$1('baseLotSize'),
+ u64$1('quoteLotSize'),
+ u64$1('feeRateBps'),
+ u64$1('referrerRebatesAccrued'),
+ blob(7),
+]);
+
+// AMM 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
+const AMM_LAYOUT = struct([
+ u64$1('status'),
+ u64$1('nonce'),
+ u64$1('maxOrder'),
+ u64$1('depth'),
+ u64$1('baseDecimal'),
+ u64$1('quoteDecimal'),
+ u64$1('state'),
+ u64$1('resetFlag'),
+ u64$1('minSize'),
+ u64$1('volMaxCutRatio'),
+ u64$1('amountWaveRatio'),
+ u64$1('baseLotSize'),
+ u64$1('quoteLotSize'),
+ u64$1('minPriceMultiplier'),
+ u64$1('maxPriceMultiplier'),
+ u64$1('systemDecimalValue'),
+ u64$1('minSeparateNumerator'),
+ u64$1('minSeparateDenominator'),
+ u64$1('tradeFeeNumerator'),
+ u64$1('tradeFeeDenominator'),
+ u64$1('pnlNumerator'),
+ u64$1('pnlDenominator'),
+ u64$1('swapFeeNumerator'),
+ u64$1('swapFeeDenominator'),
+ u64$1('baseNeedTakePnl'),
+ u64$1('quoteNeedTakePnl'),
+ u64$1('quoteTotalPnl'),
+ u64$1('baseTotalPnl'),
+ u64$1('poolOpenTime'),
+ u64$1('punishPcAmount'),
+ u64$1('punishCoinAmount'),
+ u64$1('orderbookToInitTime'),
+ u128('swapBaseInAmount'),
+ u128('swapQuoteOutAmount'),
+ u64$1('swapBase2QuoteFee'),
+ u128('swapQuoteInAmount'),
+ u128('swapBaseOutAmount'),
+ u64$1('swapQuote2BaseFee'),
+ // amm vault
+ publicKey('baseVault'),
+ publicKey('quoteVault'),
+ // mint
+ publicKey('baseMint'),
+ publicKey('quoteMint'),
+ publicKey('lpMint'),
+ // market
+ publicKey('openOrders'),
+ publicKey('marketId'),
+ publicKey('marketProgramId'),
+ publicKey('targetOrders'),
+ publicKey('withdrawQueue'),
+ publicKey('lpVault'),
+ publicKey('owner'),
+ // true circulating supply without lock up
+ u64$1('lpReserve'),
+ seq(u64$1(), 3, 'padding'),
+]);
+
+// CP_AMM CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
+const CPAMM_LAYOUT = struct([
+ blob(8),
+ publicKey("configId"),
+ publicKey("poolCreator"),
+ publicKey("vaultA"),
+ publicKey("vaultB"),
+ publicKey("mintLp"),
+ publicKey("mintA"),
+ publicKey("mintB"),
+ publicKey("mintProgramA"),
+ publicKey("mintProgramB"),
+ publicKey("observationId"),
+ u8("bump"),
+ u8("status"),
+ u8("lpDecimals"),
+ u8("mintDecimalA"),
+ u8("mintDecimalB"),
+ u64$1("lpAmount"),
+ u64$1("protocolFeesMintA"),
+ u64$1("protocolFeesMintB"),
+ u64$1("fundFeesMintA"),
+ u64$1("fundFeesMintB"),
+ u64$1("openTime"),
+ seq(u64$1(), 32),
+]);
+
+// CLMM
+
+const RewardInfo = struct([
+ u8("rewardState"),
+ u64$1("openTime"),
+ u64$1("endTime"),
+ u64$1("lastUpdateTime"),
+ u128("emissionsPerSecondX64"),
+ u64$1("rewardTotalEmissioned"),
+ u64$1("rewardClaimed"),
+ publicKey("tokenMint"),
+ publicKey("tokenVault"),
+ publicKey("creator"),
+ u128("rewardGrowthGlobalX64"),
+]);
+
+const CLMM_LAYOUT = struct([
+ blob(8),
+ u8("bump"),
+ publicKey("ammConfig"),
+ publicKey("creator"),
+ publicKey("mintA"),
+ publicKey("mintB"),
+ publicKey("vaultA"),
+ publicKey("vaultB"),
+ publicKey("observationId"),
+ u8("mintDecimalsA"),
+ u8("mintDecimalsB"),
+ u16("tickSpacing"),
+ u128("liquidity"),
+ u128("sqrtPriceX64"),
+ i32("tickCurrent"),
+ u32(),
+ u128("feeGrowthGlobalX64A"),
+ u128("feeGrowthGlobalX64B"),
+ u64$1("protocolFeesTokenA"),
+ u64$1("protocolFeesTokenB"),
+ u128("swapInAmountTokenA"),
+ u128("swapOutAmountTokenB"),
+ u128("swapInAmountTokenB"),
+ u128("swapOutAmountTokenA"),
+ u8("status"),
+ seq(u8(), 7, ""),
+ seq(RewardInfo, 3, "rewardInfos"),
+ seq(u64$1(), 16, "tickArrayBitmap"),
+ u64$1("totalFeesTokenA"),
+ u64$1("totalFeesClaimedTokenA"),
+ u64$1("totalFeesTokenB"),
+ u64$1("totalFeesClaimedTokenB"),
+ u64$1("fundFeesTokenA"),
+ u64$1("fundFeesTokenB"),
+ u64$1("startTime"),
+ seq(u64$1(), 15 * 4 - 3, "padding"),
+]);
+
+function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+
+const LIQUIDITY_FEES_NUMERATOR = new BN(25);
+const LIQUIDITY_FEES_DENOMINATOR = new BN(10000);
+
+const BNDivCeil = (bn1, bn2)=> {
+ const { div, mod } = bn1.divmod(bn2);
+
+ if (mod.gt(new BN(0))) {
+ return div.add(new BN(1))
+ } else {
+ return div
+ }
+};
+
+const getPairs = (base, quote)=>{
+ return request(`solana://675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8/getProgramAccounts`, {
+ params: { filters: [
+ { dataSize: AMM_LAYOUT.span },
+ { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6 (Swap)
+ { memcmp: { offset: 400, bytes: base }},
+ { memcmp: { offset: 432, bytes: quote }},
+ ]},
+ api: AMM_LAYOUT,
+ cache: 86400, // 24h,
+ cacheKey: ['raydium', base.toString(), quote.toString()].join('-')
+ })
+};
+
+const getPairsWithPrice$3 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ let accounts = await getPairs(tokenIn, tokenOut);
+
+ if(accounts.length == 0) {
+ accounts = await getPairs(tokenOut, tokenIn);
+ }
+
+ const pairs = await Promise.all(accounts.map(async(account)=>{
+
+ const baseMint = account.data.baseMint.toString();
+ const quoteMint = account.data.quoteMint.toString();
+
+ const balances = await Promise.all([
+ request(`solana://${account.data.baseVault.toString()}/getTokenAccountBalance`, { cache: 5 }),
+ request(`solana://${account.data.quoteVault.toString()}/getTokenAccountBalance`, { cache: 5 })
+ ]);
+ const baseReserve = (_optionalChain$1([balances, 'access', _ => _[0], 'optionalAccess', _2 => _2.value, 'optionalAccess', _3 => _3.amount]) ? new BN(_optionalChain$1([balances, 'access', _4 => _4[0], 'optionalAccess', _5 => _5.value, 'optionalAccess', _6 => _6.amount])) : new BN(0)).sub(account.data.baseNeedTakePnl);
+ const quoteReserve = (_optionalChain$1([balances, 'access', _7 => _7[1], 'optionalAccess', _8 => _8.value, 'optionalAccess', _9 => _9.amount]) ? new BN(_optionalChain$1([balances, 'access', _10 => _10[1], 'optionalAccess', _11 => _11.value, 'optionalAccess', _12 => _12.amount])) : new BN(0)).sub(account.data.quoteNeedTakePnl);
+
+ if(baseMint === Blockchains.solana.wrapped.address) {
+ if(baseReserve.lt(new BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (quoteMint === Blockchains.solana.wrapped.address) {
+ if(quoteReserve.lt(new BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (Blockchains.solana.stables.usd.includes(baseMint)) {
+ if((parseFloat(baseReserve.toString()) / 10 ** account.data.baseDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ } else if (Blockchains.solana.stables.usd.includes(quoteMint)) {
+ if((parseFloat(quoteReserve.toString()) / 10 ** account.data.quoteDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ }
+
+ const reserves = [baseReserve, quoteReserve];
+
+ if(tokenOut === baseMint) {
+ reserves.reverse();
+ }
+
+ const [reserveIn, reserveOut] = reserves;
+
+ let price;
+ if(amountOut || amountOutMin) { // compute amountIn
+
+ new BN(0);
+ let amountOutRaw = new BN((amountOut || amountOutMin).toString());
+
+ if (amountOutRaw.gt(reserveOut)) {
+ amountOutRaw = reserveOut.sub(new BN(1));
+ }
+
+ const denominator = reserveOut.sub(amountOutRaw);
+ const amountInWithoutFee = reserveIn.mul(amountOutRaw).div(denominator);
+
+ price = amountInWithoutFee
+ .mul(LIQUIDITY_FEES_DENOMINATOR)
+ .div(LIQUIDITY_FEES_DENOMINATOR.sub(LIQUIDITY_FEES_NUMERATOR))
+ .toString();
+
+ } else { // compute amountOut
+
+ new BN(0);
+ const amountInRaw = new BN((amountIn || amountInMin).toString());
+ const feeRaw = BNDivCeil(amountInRaw.mul(LIQUIDITY_FEES_NUMERATOR), LIQUIDITY_FEES_DENOMINATOR);
+
+ const amountInWithFee = amountInRaw.sub(feeRaw);
+ const denominator = reserveIn.add(amountInWithFee);
+
+ price = reserveOut.mul(amountInWithFee).div(denominator).toString();
+ }
+
+ return {
+ publicKey: account.pubkey.toString(),
+ baseMint,
+ quoteMint,
+ price,
+ data: account.data
+ }
+
+ }));
+
+ return pairs.filter(Boolean)
+};
+
+const getPairsWithPrice$2 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+};
+
+const getPairsWithPrice$1 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+};
+
+const getParisWithPriceForAllTypes = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ return Promise.all([
+ getPairsWithPrice$3({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$2({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$1({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ ]).then((pairsAMM, pairsCPAMM, pairsCLMNN)=>{
+ return [
+ (pairsAMM || []).filter(Boolean).flat(),
+ (pairsCPAMM || []).filter(Boolean).flat(),
+ (pairsCLMNN || []).filter(Boolean).flat()
+ ].flat()
+ })
+};
+
+const getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ try {
+ return await getParisWithPriceForAllTypes({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })
+ } catch (e) {
+ return []
+ }
+};
+
+let getHighestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).gt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+};
+
+let getLowestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).lt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+};
+
+let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+
+ if(!pairs || pairs.length === 0) { return }
+
+ let bestPair;
+
+ if(amountIn || amountInMax) {
+ bestPair = getHighestPrice(pairs);
+ } else { // amount out
+ bestPair = getLowestPrice(pairs);
+ }
+
+ return bestPair
+};
+
+function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+const blockchain$1 = Blockchains.solana;
+
+// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
+//
+// We keep 11111111111111111111111111111111 internally
+// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
+// as they are not the same!
+//
+let getExchangePath = ({ path }) => {
+ if(!path) { return }
+ let exchangePath = path.map((token, index) => {
+ if (
+ token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
+ path[index-1] != blockchain$1.wrapped.address
+ ) {
+ return blockchain$1.wrapped.address
+ } else {
+ return token
+ }
+ });
+
+ if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ exchangePath.splice(0, 1);
+ } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ exchangePath.splice(exchangePath.length-1, 1);
+ }
+
+ return exchangePath
+};
+
+let pathExists = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ if(path.length == 1) { return false }
+ path = getExchangePath({ path });
+ if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ return true
+ } else {
+ return false
+ }
+};
+
+let findPath = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ if(
+ [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ ) { return { path: undefined, exchangePath: undefined } }
+
+ let path, stablesIn, stablesOut, stable;
+
+ if (await pathExists({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ // direct path
+ path = [tokenIn, tokenOut];
+ } else if (
+ tokenIn != blockchain$1.wrapped.address &&
+ tokenIn != blockchain$1.currency.address &&
+ await pathExists({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$1.wrapped.address &&
+ tokenOut != blockchain$1.currency.address &&
+ await pathExists({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ ) {
+ // path via blockchain.wrapped.address
+ path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ } else if (
+ !blockchain$1.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$1.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ (stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
+ ) {
+ // path via TOKEN_IN <> STABLE <> TOKEN_OUT
+ path = [tokenIn, stable, tokenOut];
+ }
+
+ // Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
+ // because that actually reflects how things are routed in reality:
+ if(_optionalChain([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
+ path.splice(1, 0, blockchain$1.wrapped.address);
+ } else if(_optionalChain([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
+ path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ }
+ return { path, exchangePath: getExchangePath({ path }) }
+};
+
+let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+
+ let amounts = [ethers.BigNumber.from(amountIn || amountInMax)];
+
+ let bestPair = await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts
+};
+
+let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+
+ path = path.slice().reverse();
+ let amounts = [ethers.BigNumber.from(amountOut || amountOutMin)];
+
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts.slice().reverse()
+};
+
+let getAmounts = async ({
+ path,
+ tokenIn,
+ tokenOut,
+ amountOut,
+ amountIn,
+ amountInMax,
+ amountOutMin
+}) => {
+ path = getExchangePath({ path });
+ let amounts;
+ if (amountOut) {
+ amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if (amountIn) {
+ amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ } else if(amountOutMin) {
+ amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if(amountInMax) {
+ amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ }
+ return {
+ amountOut: (amountOut || amountOutMin),
+ amountIn: (amountIn || amountInMax),
+ amountInMax: (amountInMax || amountIn),
+ amountOutMin: (amountOutMin || amountOut),
+ amounts
+ }
+};
+
+const blockchain = Blockchains.solana;
+
+const getTransaction = async({
+ path,
+ amountIn,
+ amountInMax,
+ amountOut,
+ amountOutMin,
+ amounts,
+ amountInInput,
+ amountOutInput,
+ amountInMaxInput,
+ amountOutMinInput,
+ account
+})=>{
+ let transaction = { blockchain: 'solana' };
+ let instructions = [];
+
+ const exchangePath = getExchangePath({ path });
+ if(exchangePath.length > 3) { throw 'Raydium can only handle fixed paths with a max length of 3 (2 pools)!' }
+ const tokenIn = exchangePath[0];
+ const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
+ const tokenOut = exchangePath[exchangePath.length-1];
+
+ let pairs;
+ if(exchangePath.length == 2) {
+ pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ } else {
+ if(amountInInput || amountInMaxInput) {
+ pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ } else { // originally amountOut
+ pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ }
+ }
+
+ let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let wrappedAccount;
+ const provider = await getProvider('solana');
+
+ if(startsWrapped || endsUnwrapped) {
+ const rent = await provider.getMinimumBalanceForRentExemption(Token.solana.TOKEN_LAYOUT.span);
+ const keypair = Keypair.generate();
+ wrappedAccount = keypair.publicKey.toString();
+ const lamports = startsWrapped ? new BN(amountIn.toString()).add(new BN(rent)) : new BN(rent);
+ let createAccountInstruction = SystemProgram.createAccount({
+ fromPubkey: new PublicKey(account),
+ newAccountPubkey: new PublicKey(wrappedAccount),
+ programId: new PublicKey(Token.solana.TOKEN_PROGRAM),
+ space: Token.solana.TOKEN_LAYOUT.span,
+ lamports
+ });
+ createAccountInstruction.signers = [keypair];
+ instructions.push(createAccountInstruction);
+ instructions.push(
+ Token.solana.initializeAccountInstruction({
+ account: wrappedAccount,
+ token: blockchain.wrapped.address,
+ owner: account
+ })
+ );
+ }
+
+ if(pairs.length === 1) { // single hop
+ const tokenAccountIn = startsWrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenIn }));
+ const tokenAccountOut = endsUnwrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenOut }));
+ const pool = pairs[0];
+ await request(`solana://${pool.data.marketId}/getAccountInfo`, { api: MARKET_LAYOUT });
+
+ let LAYOUT, data;
+ LAYOUT = struct([
+ u8('instruction'),
+ u64$1('amountIn'),
+ u64$1('minAmountOut')
+ ]);
+ data = Buffer.alloc(LAYOUT.span);
+ LAYOUT.encode(
+ {
+ instruction: 9,
+ amountIn: new BN((amountIn || amountInMax).toString()),
+ minAmountOut: new BN((amountOutMin || amountOut).toString()),
+ },
+ data,
+ );
+
+ // if(!endsUnwrapped) {
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenOut, account: tokenAccountOut })
+ // }
+
+ // let keys = [
+ // // token_program
+ // { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // // amm
+ // { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // // amm authority
+ // { pubkey: await getAssociatedAuthority(new PublicKey(pool.publicKey)), isWritable: false, isSigner: false },
+ // // amm openOrders
+ // { pubkey: new PublicKey(pool.data.openOrders), isWritable: true, isSigner: false },
+ // // amm baseVault
+ // { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // // amm quoteVault
+ // { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // // openbook marketProgramId
+ // { pubkey: new PublicKey(pool.data.marketProgramId), isWritable: false, isSigner: false },
+ // // openbook marketId
+ // { pubkey: new PublicKey(pool.data.marketId), isWritable: true, isSigner: false },
+ // // openbook marketBids
+ // { pubkey: market.bids, isWritable: true, isSigner: false },
+ // // openbook marketAsks
+ // { pubkey: market.asks, isWritable: true, isSigner: false },
+ // // openbook eventQueue
+ // { pubkey: market.eventQueue, isWritable: true, isSigner: false },
+ // // openbook baseVault
+ // { pubkey: market.baseVault, isWritable: true, isSigner: false },
+ // // openbook quoteVault
+ // { pubkey: market.quoteVault, isWritable: true, isSigner: false },
+ // // openbook marketAuthority
+ // { pubkey: await getAssociatedMarketAuthority(pool.data.marketProgramId, pool.data.marketId), isWritable: false, isSigner: false },
+ // // user tokenAccountIn
+ // { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // // user tokenAccountOut
+ // { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // // user owner
+ // { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ // ]
+
+ let keys = [
+ // token_program
+ { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // amm
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm authority
+ { pubkey: new PublicKey('5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1'), isWritable: false, isSigner: false },
+ // amm openOrders
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm baseVault
+ { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // amm quoteVault
+ { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // openbook marketProgramId
+ { pubkey: new PublicKey(pool.publicKey), isWritable: false, isSigner: false },
+ // openbook marketId
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketBids
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAsks
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook eventQueue
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook baseVault
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook quoteVault
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAuthority
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // user tokenAccountIn
+ { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // user tokenAccountOut
+ { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // user owner
+ { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ ];
+
+ console.log('keys', JSON.stringify(keys));
+
+ instructions.push(
+ new TransactionInstruction({
+ programId: new PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'),
+ keys,
+ data,
+ })
+ );
+ } else if (pairs.length === 2) ;
+
+ if(startsWrapped || endsUnwrapped) {
+ instructions.push(
+ Token.solana.closeAccountInstruction({
+ account: wrappedAccount,
+ owner: account
+ })
+ );
+ }
+
+ // await debug(instructions, provider)
+
+ transaction.instructions = instructions;
+ return transaction
+};
+
+var Raydium = {
+ findPath,
+ pathExists,
+ getAmounts,
+ getTransaction,
+ AMM_LAYOUT,
+ CPAMM_LAYOUT,
+ CLMM_LAYOUT,
+ MARKET_LAYOUT,
+};
+
+// // AMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_amm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_amm.api.span },
+// { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6
+// { memcmp: { offset: 400, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 432, bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_amm.api,
+// })
+// console.log(accounts)
+
+
+// // CPAMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_cpamm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_cpamm.api.span },
+// { memcmp: { offset: 168, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 200, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_cpamm.api,
+// })
+// console.log(accounts)
+
+
+// // CLMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_clmm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_clmm.api.span },
+// { memcmp: { offset: 73, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 105, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_clmm.api,
+// })
+// console.log(accounts)
+
+const exchange = {
+
+ name: 'raydium',
+ label: 'Raydium',
+ logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjMzIiB2aWV3Qm94PSIwIDAgMjkgMzMiIHdpZHRoPSIyOSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjI4LjMxNjgiIHgyPSItMS43MzMzNiIgeTE9IjguMTkxNjIiIHkyPSIyMC4yMDg2Ij48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNjMjAwZmIiLz48c3RvcCBvZmZzZXQ9Ii40ODk2NTgiIHN0b3AtY29sb3I9IiMzNzcyZmYiLz48c3RvcCBvZmZzZXQ9Ii40ODk3NTgiIHN0b3AtY29sb3I9IiMzNzczZmUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM1YWM0YmUiLz48L2xpbmVhckdyYWRpZW50PjxnIGZpbGw9InVybCgjYSkiPjxwYXRoIGQ9Im0yNi44NjI1IDEyLjI4MXYxMS40MTA0bC0xMi42OTE2IDcuMzI2MS0xMi42OTg1OS03LjMyNjF2LTE0LjY1OTM3bDEyLjY5ODU5LTcuMzMzMjIgOS43NTQxIDUuNjM0NDEgMS40NzIzLS44NDk0MS0xMS4yMjY0LTYuNDgzODEtMTQuMTcwOSA4LjE4MjYydjE2LjM1ODE4bDE0LjE3MDkgOC4xODI2IDE0LjE3MS04LjE4MjZ2LTEzLjEwOTJ6Ii8+PHBhdGggZD0ibTEwLjYxNzYgMjMuNjk4NWgtMi4xMjM1M3YtNy4xMjA5aDcuMDc4NDNjLjY2OTctLjAwNzQgMS4zMDk1LS4yNzgyIDEuNzgxMS0uNzUzOC40NzE2LS40NzU1LjczNy0xLjExNzYuNzM4OC0xLjc4NzQuMDAzOC0uMzMxMS0uMDYwMS0uNjU5Ni0uMTg3OS0uOTY1MS0uMTI3OS0uMzA1Ni0uMzE2OC0uNTgxNy0uNTU1NC0uODExNS0uMjMwOC0uMjM3Mi0uNTA3MS0uNDI1My0uODEyNC0uNTUzLS4zMDUzLS4xMjc4LS42MzMzLS4xOTI1LS45NjQyLS4xOTAzaC03LjA3ODQzdi0yLjE2NTk1aDcuMDg1NDNjMS4yNDA1LjAwNzQzIDIuNDI4MS41MDM1MSAzLjMwNTMgMS4zODA2NS44NzcxLjg3NzIgMS4zNzMyIDIuMDY0OCAxLjM4MDYgMy4zMDUyLjAwNzYuOTQ5Ni0uMjgxOSAxLjg3NzctLjgyODEgMi42NTQ0LS41MDI3Ljc0MzItMS4yMTExIDEuMzIzNy0yLjAzODYgMS42NzA1LS44MTk0LjI1OTktMS42NzQ1LjM4ODktMi41MzQxLjM4MjNoLTQuMjQ3eiIvPjxwYXRoIGQ9Im0yMC4yMTU5IDIzLjUyMTVoLTIuNDc3NWwtMS45MTExLTMuMzMzOWMuNzU2MS0uMDQ2MyAxLjUwMTktLjE5ODggMi4yMTU1LS40NTN6Ii8+PHBhdGggZD0ibTI1LjM4MzEgOS45MDk3NSAxLjQ2NTIuODE0MDUgMS40NjUzLS44MTQwNXYtMS43MjAwNWwtMS40NjUzLS44NDk0MS0xLjQ2NTIuODQ5NDF6Ii8+PC9nPjwvc3ZnPg==',
+ protocol: 'raydium',
+
+ slippage: true,
+
+ blockchains: ['solana'],
+
+ solana: {
+
+ router_amm: {
+ address: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
+ api: Raydium.AMM_LAYOUT,
+ },
+
+ router_cpamm: {
+ address: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C',
+ api: Raydium.CPAMM_LAYOUT
+ },
+
+ router_clmm: {
+ address: 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK',
+ api: Raydium.CLMM_LAYOUT
+ },
+ }
+};
+
+var raydium = (scope)=>{
+
return new Exchange(
Object.assign(exchange, {
scope,
- findPath: (args)=>Orca.findPath({ ...args, exchange }),
- pathExists: (args)=>Orca.pathExists({ ...args, exchange }),
- getAmounts: (args)=>Orca.getAmounts({ ...args, exchange }),
+ findPath: (args)=>Raydium.findPath({ ...args, exchange }),
+ pathExists: (args)=>Raydium.pathExists({ ...args, exchange }),
+ getAmounts: (args)=>Raydium.getAmounts({ ...args, exchange }),
getPrep: (args)=>{},
- getTransaction: (args)=>Orca.getTransaction({ ...args, exchange }),
+ getTransaction: (args)=>Raydium.getTransaction({ ...args, exchange }),
})
)
};
const exchanges = [
orca(),
+ raydium(),
];
exchanges.forEach((exchange)=>{
exchanges[exchange.name] = exchange;
@@ -2225,6 +3035,7 @@ exchanges.forEach((exchange)=>{
exchanges.solana = [
orca('solana'),
+ raydium('solana'),
];
exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchange; });
diff --git a/dist/umd/index.evm.js b/dist/umd/index.evm.js
index 21bfad6..d10210a 100644
--- a/dist/umd/index.evm.js
+++ b/dist/umd/index.evm.js
@@ -312,7 +312,10 @@
let amounts; // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch (e) { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
diff --git a/dist/umd/index.js b/dist/umd/index.js
index 1c1a124..4689c42 100644
--- a/dist/umd/index.js
+++ b/dist/umd/index.js
@@ -10,7 +10,7 @@
var Blockchains__default = /*#__PURE__*/_interopDefaultLegacy(Blockchains);
var Decimal__default = /*#__PURE__*/_interopDefaultLegacy(Decimal);
- function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
+ function _optionalChain$7(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
constructor({
blockchain,
tokenIn,
@@ -36,10 +36,10 @@
this.decimalsOut = decimalsOut;
this.path = path;
this.pools = pools;
- this.amountIn = _optionalChain$5([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
- this.amountOutMin = _optionalChain$5([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
- this.amountOut = _optionalChain$5([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
- this.amountInMax = _optionalChain$5([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
+ this.amountIn = _optionalChain$7([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
+ this.amountOutMin = _optionalChain$7([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
+ this.amountOut = _optionalChain$7([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
+ this.amountInMax = _optionalChain$7([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
this.exchange = exchange;
this.getPrep = getPrep;
this.getTransaction = getTransaction;
@@ -313,7 +313,10 @@
let amounts; // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch (e) { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
@@ -437,7 +440,7 @@
}
}
- function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+ function _optionalChain$6(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
// Replaces 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE with the wrapped token and implies wrapping.
//
@@ -445,7 +448,7 @@
// to be able to differentiate between ETH<>Token and WETH<>Token swaps
// as they are not the same!
//
- const getExchangePath$4 = ({ blockchain, exchange, path }) => {
+ const getExchangePath$5 = ({ blockchain, exchange, path }) => {
if(!path) { return }
let exchangePath = path.map((token, index) => {
if (
@@ -477,8 +480,8 @@
}
};
- const pathExists$5 = async ({ blockchain, exchange, path }) => {
- const exchangePath = getExchangePath$4({ blockchain, exchange, path });
+ const pathExists$6 = async ({ blockchain, exchange, path }) => {
+ const exchangePath = getExchangePath$5({ blockchain, exchange, path });
if(!exchangePath || exchangePath.length === 1) { return false }
try {
let pair = await web3Client.request({
@@ -487,7 +490,7 @@
method: 'getPair',
api: exchange[blockchain].factory.api,
cache: 3600000,
- params: getExchangePath$4({ blockchain, exchange, path }),
+ params: getExchangePath$5({ blockchain, exchange, path }),
});
if(!pair || pair == Blockchains__default['default'][blockchain].zero) { return false }
let [reserves, token0, token1] = await Promise.all([
@@ -508,61 +511,61 @@
} catch (e){ console.log('e', e); return false }
};
- const findPath$5 = async ({ blockchain, exchange, tokenIn, tokenOut }) => {
+ const findPath$6 = async ({ blockchain, exchange, tokenIn, tokenOut }) => {
if(
[tokenIn, tokenOut].includes(Blockchains__default['default'][blockchain].currency.address) &&
[tokenIn, tokenOut].includes(Blockchains__default['default'][blockchain].wrapped.address)
) { return { path: undefined, exchangePath: undefined } }
let path;
- if (await pathExists$5({ blockchain, exchange, path: [tokenIn, tokenOut] })) {
+ if (await pathExists$6({ blockchain, exchange, path: [tokenIn, tokenOut] })) {
// direct path
path = [tokenIn, tokenOut];
} else if (
tokenIn != Blockchains__default['default'][blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [tokenIn, Blockchains__default['default'][blockchain].wrapped.address] }) &&
+ await pathExists$6({ blockchain, exchange, path: [tokenIn, Blockchains__default['default'][blockchain].wrapped.address] }) &&
tokenOut != Blockchains__default['default'][blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [tokenOut, Blockchains__default['default'][blockchain].wrapped.address] })
+ await pathExists$6({ blockchain, exchange, path: [tokenOut, Blockchains__default['default'][blockchain].wrapped.address] })
) {
// path via WRAPPED
path = [tokenIn, Blockchains__default['default'][blockchain].wrapped.address, tokenOut];
} else if (
!Blockchains__default['default'][blockchain].stables.usd.includes(tokenIn) &&
- (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map((stable)=>pathExists$5({ blockchain, exchange, path: [tokenIn, stable] })))).filter(Boolean).length &&
+ (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map((stable)=>pathExists$6({ blockchain, exchange, path: [tokenIn, stable] })))).filter(Boolean).length &&
tokenOut != Blockchains__default['default'][blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [Blockchains__default['default'][blockchain].wrapped.address, tokenOut] })
+ await pathExists$6({ blockchain, exchange, path: [Blockchains__default['default'][blockchain].wrapped.address, tokenOut] })
) {
// path via tokenIn -> USD -> WRAPPED -> tokenOut
- let USD = (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$5({ blockchain, exchange, path: [tokenIn, stable] }) ? stable : undefined) }))).find(Boolean);
+ let USD = (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$6({ blockchain, exchange, path: [tokenIn, stable] }) ? stable : undefined) }))).find(Boolean);
path = [tokenIn, USD, Blockchains__default['default'][blockchain].wrapped.address, tokenOut];
} else if (
tokenIn != Blockchains__default['default'][blockchain].wrapped.address &&
- await pathExists$5({ blockchain, exchange, path: [tokenIn, Blockchains__default['default'][blockchain].wrapped.address] }) &&
+ await pathExists$6({ blockchain, exchange, path: [tokenIn, Blockchains__default['default'][blockchain].wrapped.address] }) &&
!Blockchains__default['default'][blockchain].stables.usd.includes(tokenOut) &&
- (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map((stable)=>pathExists$5({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
+ (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map((stable)=>pathExists$6({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
) {
// path via tokenIn -> WRAPPED -> USD -> tokenOut
- let USD = (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$5({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
+ let USD = (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$6({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
path = [tokenIn, Blockchains__default['default'][blockchain].wrapped.address, USD, tokenOut];
} else if (
tokenIn != Blockchains__default['default'][blockchain].wrapped.address &&
tokenIn === Blockchains__default['default'][blockchain].currency.address &&
!Blockchains__default['default'][blockchain].stables.usd.includes(tokenOut) &&
- (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map((stable)=>pathExists$5({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
+ (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map((stable)=>pathExists$6({ blockchain, exchange, path: [stable, tokenOut] })))).filter(Boolean).length
) {
- let USD = (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$5({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
+ let USD = (await Promise.all(Blockchains__default['default'][blockchain].stables.usd.map(async (stable)=>{ return(await pathExists$6({ blockchain, exchange, path: [stable, tokenOut] }) ? stable : undefined) }))).find(Boolean);
path = [tokenIn, USD, tokenOut];
}
// Add WRAPPED to route path if things start or end with NATIVE
// because that actually reflects how things are routed in reality:
- if(_optionalChain$4([path, 'optionalAccess', _ => _.length]) && path[0] == Blockchains__default['default'][blockchain].currency.address) {
+ if(_optionalChain$6([path, 'optionalAccess', _ => _.length]) && path[0] == Blockchains__default['default'][blockchain].currency.address) {
path.splice(1, 0, Blockchains__default['default'][blockchain].wrapped.address);
- } else if(_optionalChain$4([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == Blockchains__default['default'][blockchain].currency.address) {
+ } else if(_optionalChain$6([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == Blockchains__default['default'][blockchain].currency.address) {
path.splice(path.length-1, 0, Blockchains__default['default'][blockchain].wrapped.address);
}
- return { path, exchangePath: getExchangePath$4({ blockchain, exchange, path }) }
+ return { path, exchangePath: getExchangePath$5({ blockchain, exchange, path }) }
};
let getAmountOut$3 = ({ blockchain, exchange, path, amountIn, tokenIn, tokenOut }) => {
@@ -574,7 +577,7 @@
api: exchange[blockchain].router.api,
params: {
amountIn: amountIn,
- path: getExchangePath$4({ blockchain, exchange, path }),
+ path: getExchangePath$5({ blockchain, exchange, path }),
},
})
.then((amountsOut)=>{
@@ -593,7 +596,7 @@
api: exchange[blockchain].router.api,
params: {
amountOut: amountOut,
- path: getExchangePath$4({ blockchain, exchange, path }),
+ path: getExchangePath$5({ blockchain, exchange, path }),
},
block
})
@@ -602,7 +605,7 @@
})
};
- let getAmounts$5 = async ({
+ let getAmounts$6 = async ({
blockchain,
exchange,
path,
@@ -679,7 +682,7 @@
};
- let getTransaction$5 = ({
+ let getTransaction$6 = ({
exchange,
blockchain,
path,
@@ -730,7 +733,7 @@
}
transaction.params = Object.assign({}, transaction.params, {
- path: getExchangePath$4({ blockchain, exchange, path }),
+ path: getExchangePath$5({ blockchain, exchange, path }),
to: account,
deadline: Math.round(Date.now() / 1000) + 60 * 60 * 24, // 24 hours
});
@@ -743,17 +746,17 @@
const PAIR$1 = [{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"sync","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}];
var UniswapV2 = {
- findPath: findPath$5,
- pathExists: pathExists$5,
- getAmounts: getAmounts$5,
+ findPath: findPath$6,
+ pathExists: pathExists$6,
+ getAmounts: getAmounts$6,
getPrep: getPrep$3,
- getTransaction: getTransaction$5,
+ getTransaction: getTransaction$6,
ROUTER: ROUTER$3,
FACTORY: FACTORY$3,
PAIR: PAIR$1,
};
- const exchange$h = {
+ const exchange$i = {
name: 'honeyswap',
label: 'Honeyswap',
@@ -783,13 +786,13 @@
return new Exchange(
- Object.assign(exchange$h, {
+ Object.assign(exchange$i, {
scope,
- findPath: (args)=>UniswapV2.findPath({ ...args, exchange: exchange$h }),
- pathExists: (args)=>UniswapV2.pathExists({ ...args, exchange: exchange$h }),
- getAmounts: (args)=>UniswapV2.getAmounts({ ...args, exchange: exchange$h }),
- getPrep: (args)=>UniswapV2.getPrep({ ...args, exchange: exchange$h }),
- getTransaction: (args)=>UniswapV2.getTransaction({ ...args, exchange: exchange$h }),
+ findPath: (args)=>UniswapV2.findPath({ ...args, exchange: exchange$i }),
+ pathExists: (args)=>UniswapV2.pathExists({ ...args, exchange: exchange$i }),
+ getAmounts: (args)=>UniswapV2.getAmounts({ ...args, exchange: exchange$i }),
+ getPrep: (args)=>UniswapV2.getPrep({ ...args, exchange: exchange$i }),
+ getTransaction: (args)=>UniswapV2.getTransaction({ ...args, exchange: exchange$i }),
})
)
};
@@ -1949,7 +1952,7 @@
return accounts
};
- let getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ let getPairsWithPrice$4 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
try {
let accounts = await getAccounts(tokenIn, tokenOut);
if(accounts.length === 0) { accounts = await getAccounts(tokenOut, tokenIn); }
@@ -1976,32 +1979,31 @@
}
};
- let getHighestPrice = (pairs)=>{
+ let getHighestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).gt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
- let getLowestPrice = (pairs)=>{
+ let getLowestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).lt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
- let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
- const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+ let getBestPair$1 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice$4({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
if(!pairs || pairs.length === 0) { return }
let bestPair;
if(amountIn || amountInMax) {
- bestPair = getHighestPrice(pairs);
+ bestPair = getHighestPrice$1(pairs);
} else { // amount out
- bestPair = getLowestPrice(pairs);
+ bestPair = getLowestPrice$1(pairs);
}
-
return bestPair
};
- function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
- const blockchain$1 = Blockchains__default['default'].solana;
+ function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+ const blockchain$3 = Blockchains__default['default'].solana;
// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
//
@@ -2009,64 +2011,64 @@
// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
// as they are not the same!
//
- let getExchangePath$3 = ({ path }) => {
+ let getExchangePath$4 = ({ path }) => {
if(!path) { return }
let exchangePath = path.map((token, index) => {
if (
- token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
- path[index-1] != blockchain$1.wrapped.address
+ token === blockchain$3.currency.address && path[index+1] != blockchain$3.wrapped.address &&
+ path[index-1] != blockchain$3.wrapped.address
) {
- return blockchain$1.wrapped.address
+ return blockchain$3.wrapped.address
} else {
return token
}
});
- if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ if(exchangePath[0] == blockchain$3.currency.address && exchangePath[1] == blockchain$3.wrapped.address) {
exchangePath.splice(0, 1);
- } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ } else if(exchangePath[exchangePath.length-1] == blockchain$3.currency.address && exchangePath[exchangePath.length-2] == blockchain$3.wrapped.address) {
exchangePath.splice(exchangePath.length-1, 1);
}
return exchangePath
};
- let pathExists$4 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ let pathExists$5 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
if(path.length == 1) { return false }
- path = getExchangePath$3({ path });
- if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ path = getExchangePath$4({ path });
+ if((await getPairsWithPrice$4({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
return true
} else {
return false
}
};
- let findPath$4 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ let findPath$5 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
if(
- [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
- [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ [tokenIn, tokenOut].includes(blockchain$3.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$3.wrapped.address)
) { return { path: undefined, exchangePath: undefined } }
let path, stablesIn, stablesOut, stable;
- if (await pathExists$4({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ if (await pathExists$5({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
// direct path
path = [tokenIn, tokenOut];
} else if (
- tokenIn != blockchain$1.wrapped.address &&
- tokenIn != blockchain$1.currency.address &&
- await pathExists$4({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
- tokenOut != blockchain$1.wrapped.address &&
- tokenOut != blockchain$1.currency.address &&
- await pathExists$4({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ tokenIn != blockchain$3.wrapped.address &&
+ tokenIn != blockchain$3.currency.address &&
+ await pathExists$5({ path: [tokenIn, blockchain$3.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$3.wrapped.address &&
+ tokenOut != blockchain$3.currency.address &&
+ await pathExists$5({ path: [tokenOut, blockchain$3.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
) {
// path via blockchain.wrapped.address
- path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ path = [tokenIn, blockchain$3.wrapped.address, tokenOut];
} else if (
- !blockchain$1.stables.usd.includes(tokenIn) &&
- (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
- !blockchain$1.stables.usd.includes(tokenOut) &&
- (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$5({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$5({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
(stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
) {
// path via TOKEN_IN <> STABLE <> TOKEN_OUT
@@ -2075,22 +2077,26 @@
// Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
// because that actually reflects how things are routed in reality:
- if(_optionalChain$3([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
- path.splice(1, 0, blockchain$1.wrapped.address);
- } else if(_optionalChain$3([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
- path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ if(_optionalChain$5([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$3.currency.address) {
+ path.splice(1, 0, blockchain$3.wrapped.address);
+ } else if(_optionalChain$5([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$3.currency.address) {
+ path.splice(path.length-1, 0, blockchain$3.wrapped.address);
}
- return { path, exchangePath: getExchangePath$3({ path }) }
+ return { path, exchangePath: getExchangePath$4({ path }) }
};
- let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+ let getAmountsOut$1 = async ({ path, amountIn, amountInMax }) => {
let amounts = [ethers.ethers.BigNumber.from(amountIn || amountInMax)];
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -2098,15 +2104,19 @@
return amounts
};
- let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+ let getAmountsIn$1 = async({ path, amountOut, amountOutMin }) => {
path = path.slice().reverse();
let amounts = [ethers.ethers.BigNumber.from(amountOut || amountOutMin)];
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -2114,7 +2124,7 @@
return amounts.slice().reverse()
};
- let getAmounts$4 = async ({
+ let getAmounts$5 = async ({
path,
tokenIn,
tokenOut,
@@ -2123,10 +2133,10 @@
amountInMax,
amountOutMin
}) => {
- path = getExchangePath$3({ path });
+ path = getExchangePath$4({ path });
let amounts;
if (amountOut) {
- amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOut, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -2134,7 +2144,7 @@
amountInMax = amountIn;
}
} else if (amountIn) {
- amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountIn, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -2142,7 +2152,7 @@
amountOutMin = amountOut;
}
} else if(amountOutMin) {
- amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOutMin, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -2150,7 +2160,7 @@
amountInMax = amountIn;
}
} else if(amountInMax) {
- amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountInMax, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -2167,7 +2177,7 @@
}
};
- const blockchain = Blockchains__default['default'].solana;
+ const blockchain$2 = Blockchains__default['default'].solana;
const SWAP_INSTRUCTION = new solanaWeb3_js.BN("14449647541112719096");
const TWO_HOP_SWAP_INSTRUCTION = new solanaWeb3_js.BN("16635068063392030915");
@@ -2382,7 +2392,7 @@
return data
};
- const getTransaction$4 = async ({
+ const getTransaction$5 = async ({
path,
amountIn,
amountInMax,
@@ -2398,7 +2408,7 @@
let transaction = { blockchain: 'solana' };
let instructions = [];
- const exchangePath = getExchangePath$3({ path });
+ const exchangePath = getExchangePath$4({ path });
if(exchangePath.length > 3) { throw 'Orca can only handle fixed paths with a max length of 3 (2 pools)!' }
const tokenIn = exchangePath[0];
const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
@@ -2406,19 +2416,19 @@
let pairs;
if(exchangePath.length == 2) {
- pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs = [await getBestPair$1({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
} else {
if(amountInInput || amountInMaxInput) {
- pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
- pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
} else { // originally amountOut
- pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
- pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
}
}
- let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
- let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let startsWrapped = (path[0] === blockchain$2.currency.address && exchangePath[0] === blockchain$2.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain$2.currency.address && exchangePath[exchangePath.length-1] === blockchain$2.wrapped.address);
let wrappedAccount;
const provider = await web3Client.getProvider('solana');
@@ -2439,7 +2449,7 @@
instructions.push(
Token__default['default'].solana.initializeAccountInstruction({
account: wrappedAccount,
- token: blockchain.wrapped.address,
+ token: blockchain$2.wrapped.address,
owner: account
})
);
@@ -2536,14 +2546,14 @@
};
var Orca = {
- findPath: findPath$4,
- pathExists: pathExists$4,
- getAmounts: getAmounts$4,
- getTransaction: getTransaction$4,
+ findPath: findPath$5,
+ pathExists: pathExists$5,
+ getAmounts: getAmounts$5,
+ getTransaction: getTransaction$5,
WHIRLPOOL_LAYOUT,
};
- const exchange$g = {
+ const exchange$h = {
name: 'orca',
label: 'Orca',
@@ -2564,16 +2574,815 @@
var orca = (scope)=>{
+ return new Exchange(
+
+ Object.assign(exchange$h, {
+ scope,
+
+ findPath: (args)=>Orca.findPath({ ...args, exchange: exchange$h }),
+ pathExists: (args)=>Orca.pathExists({ ...args, exchange: exchange$h }),
+ getAmounts: (args)=>Orca.getAmounts({ ...args, exchange: exchange$h }),
+ getPrep: (args)=>{},
+ getTransaction: (args)=>Orca.getTransaction({ ...args, exchange: exchange$h }),
+ })
+ )
+ };
+
+ // OpenBook Market
+ const MARKET_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.blob(5),
+ solanaWeb3_js.blob(8), // accountFlagsLayout('accountFlags'),
+ solanaWeb3_js.publicKey('ownAddress'),
+ solanaWeb3_js.u64('vaultSignerNonce'),
+ solanaWeb3_js.publicKey('baseMint'),
+ solanaWeb3_js.publicKey('quoteMint'),
+ solanaWeb3_js.publicKey('baseVault'),
+ solanaWeb3_js.u64('baseDepositsTotal'),
+ solanaWeb3_js.u64('baseFeesAccrued'),
+ solanaWeb3_js.publicKey('quoteVault'),
+ solanaWeb3_js.u64('quoteDepositsTotal'),
+ solanaWeb3_js.u64('quoteFeesAccrued'),
+ solanaWeb3_js.u64('quoteDustThreshold'),
+ solanaWeb3_js.publicKey('requestQueue'),
+ solanaWeb3_js.publicKey('eventQueue'),
+ solanaWeb3_js.publicKey('bids'),
+ solanaWeb3_js.publicKey('asks'),
+ solanaWeb3_js.u64('baseLotSize'),
+ solanaWeb3_js.u64('quoteLotSize'),
+ solanaWeb3_js.u64('feeRateBps'),
+ solanaWeb3_js.u64('referrerRebatesAccrued'),
+ solanaWeb3_js.blob(7),
+ ]);
+
+ // AMM 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
+ const AMM_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.u64('status'),
+ solanaWeb3_js.u64('nonce'),
+ solanaWeb3_js.u64('maxOrder'),
+ solanaWeb3_js.u64('depth'),
+ solanaWeb3_js.u64('baseDecimal'),
+ solanaWeb3_js.u64('quoteDecimal'),
+ solanaWeb3_js.u64('state'),
+ solanaWeb3_js.u64('resetFlag'),
+ solanaWeb3_js.u64('minSize'),
+ solanaWeb3_js.u64('volMaxCutRatio'),
+ solanaWeb3_js.u64('amountWaveRatio'),
+ solanaWeb3_js.u64('baseLotSize'),
+ solanaWeb3_js.u64('quoteLotSize'),
+ solanaWeb3_js.u64('minPriceMultiplier'),
+ solanaWeb3_js.u64('maxPriceMultiplier'),
+ solanaWeb3_js.u64('systemDecimalValue'),
+ solanaWeb3_js.u64('minSeparateNumerator'),
+ solanaWeb3_js.u64('minSeparateDenominator'),
+ solanaWeb3_js.u64('tradeFeeNumerator'),
+ solanaWeb3_js.u64('tradeFeeDenominator'),
+ solanaWeb3_js.u64('pnlNumerator'),
+ solanaWeb3_js.u64('pnlDenominator'),
+ solanaWeb3_js.u64('swapFeeNumerator'),
+ solanaWeb3_js.u64('swapFeeDenominator'),
+ solanaWeb3_js.u64('baseNeedTakePnl'),
+ solanaWeb3_js.u64('quoteNeedTakePnl'),
+ solanaWeb3_js.u64('quoteTotalPnl'),
+ solanaWeb3_js.u64('baseTotalPnl'),
+ solanaWeb3_js.u64('poolOpenTime'),
+ solanaWeb3_js.u64('punishPcAmount'),
+ solanaWeb3_js.u64('punishCoinAmount'),
+ solanaWeb3_js.u64('orderbookToInitTime'),
+ solanaWeb3_js.u128('swapBaseInAmount'),
+ solanaWeb3_js.u128('swapQuoteOutAmount'),
+ solanaWeb3_js.u64('swapBase2QuoteFee'),
+ solanaWeb3_js.u128('swapQuoteInAmount'),
+ solanaWeb3_js.u128('swapBaseOutAmount'),
+ solanaWeb3_js.u64('swapQuote2BaseFee'),
+ // amm vault
+ solanaWeb3_js.publicKey('baseVault'),
+ solanaWeb3_js.publicKey('quoteVault'),
+ // mint
+ solanaWeb3_js.publicKey('baseMint'),
+ solanaWeb3_js.publicKey('quoteMint'),
+ solanaWeb3_js.publicKey('lpMint'),
+ // market
+ solanaWeb3_js.publicKey('openOrders'),
+ solanaWeb3_js.publicKey('marketId'),
+ solanaWeb3_js.publicKey('marketProgramId'),
+ solanaWeb3_js.publicKey('targetOrders'),
+ solanaWeb3_js.publicKey('withdrawQueue'),
+ solanaWeb3_js.publicKey('lpVault'),
+ solanaWeb3_js.publicKey('owner'),
+ // true circulating supply without lock up
+ solanaWeb3_js.u64('lpReserve'),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 3, 'padding'),
+ ]);
+
+ // CP_AMM CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
+ const CPAMM_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.blob(8),
+ solanaWeb3_js.publicKey("configId"),
+ solanaWeb3_js.publicKey("poolCreator"),
+ solanaWeb3_js.publicKey("vaultA"),
+ solanaWeb3_js.publicKey("vaultB"),
+ solanaWeb3_js.publicKey("mintLp"),
+ solanaWeb3_js.publicKey("mintA"),
+ solanaWeb3_js.publicKey("mintB"),
+ solanaWeb3_js.publicKey("mintProgramA"),
+ solanaWeb3_js.publicKey("mintProgramB"),
+ solanaWeb3_js.publicKey("observationId"),
+ solanaWeb3_js.u8("bump"),
+ solanaWeb3_js.u8("status"),
+ solanaWeb3_js.u8("lpDecimals"),
+ solanaWeb3_js.u8("mintDecimalA"),
+ solanaWeb3_js.u8("mintDecimalB"),
+ solanaWeb3_js.u64("lpAmount"),
+ solanaWeb3_js.u64("protocolFeesMintA"),
+ solanaWeb3_js.u64("protocolFeesMintB"),
+ solanaWeb3_js.u64("fundFeesMintA"),
+ solanaWeb3_js.u64("fundFeesMintB"),
+ solanaWeb3_js.u64("openTime"),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 32),
+ ]);
+
+ // CLMM
+
+ const RewardInfo = solanaWeb3_js.struct([
+ solanaWeb3_js.u8("rewardState"),
+ solanaWeb3_js.u64("openTime"),
+ solanaWeb3_js.u64("endTime"),
+ solanaWeb3_js.u64("lastUpdateTime"),
+ solanaWeb3_js.u128("emissionsPerSecondX64"),
+ solanaWeb3_js.u64("rewardTotalEmissioned"),
+ solanaWeb3_js.u64("rewardClaimed"),
+ solanaWeb3_js.publicKey("tokenMint"),
+ solanaWeb3_js.publicKey("tokenVault"),
+ solanaWeb3_js.publicKey("creator"),
+ solanaWeb3_js.u128("rewardGrowthGlobalX64"),
+ ]);
+
+ const CLMM_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.blob(8),
+ solanaWeb3_js.u8("bump"),
+ solanaWeb3_js.publicKey("ammConfig"),
+ solanaWeb3_js.publicKey("creator"),
+ solanaWeb3_js.publicKey("mintA"),
+ solanaWeb3_js.publicKey("mintB"),
+ solanaWeb3_js.publicKey("vaultA"),
+ solanaWeb3_js.publicKey("vaultB"),
+ solanaWeb3_js.publicKey("observationId"),
+ solanaWeb3_js.u8("mintDecimalsA"),
+ solanaWeb3_js.u8("mintDecimalsB"),
+ solanaWeb3_js.u16("tickSpacing"),
+ solanaWeb3_js.u128("liquidity"),
+ solanaWeb3_js.u128("sqrtPriceX64"),
+ solanaWeb3_js.i32("tickCurrent"),
+ solanaWeb3_js.u32(),
+ solanaWeb3_js.u128("feeGrowthGlobalX64A"),
+ solanaWeb3_js.u128("feeGrowthGlobalX64B"),
+ solanaWeb3_js.u64("protocolFeesTokenA"),
+ solanaWeb3_js.u64("protocolFeesTokenB"),
+ solanaWeb3_js.u128("swapInAmountTokenA"),
+ solanaWeb3_js.u128("swapOutAmountTokenB"),
+ solanaWeb3_js.u128("swapInAmountTokenB"),
+ solanaWeb3_js.u128("swapOutAmountTokenA"),
+ solanaWeb3_js.u8("status"),
+ solanaWeb3_js.seq(solanaWeb3_js.u8(), 7, ""),
+ solanaWeb3_js.seq(RewardInfo, 3, "rewardInfos"),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 16, "tickArrayBitmap"),
+ solanaWeb3_js.u64("totalFeesTokenA"),
+ solanaWeb3_js.u64("totalFeesClaimedTokenA"),
+ solanaWeb3_js.u64("totalFeesTokenB"),
+ solanaWeb3_js.u64("totalFeesClaimedTokenB"),
+ solanaWeb3_js.u64("fundFeesTokenA"),
+ solanaWeb3_js.u64("fundFeesTokenB"),
+ solanaWeb3_js.u64("startTime"),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 15 * 4 - 3, "padding"),
+ ]);
+
+ function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+
+ const LIQUIDITY_FEES_NUMERATOR = new solanaWeb3_js.BN(25);
+ const LIQUIDITY_FEES_DENOMINATOR = new solanaWeb3_js.BN(10000);
+
+ const BNDivCeil = (bn1, bn2)=> {
+ const { div, mod } = bn1.divmod(bn2);
+
+ if (mod.gt(new solanaWeb3_js.BN(0))) {
+ return div.add(new solanaWeb3_js.BN(1))
+ } else {
+ return div
+ }
+ };
+
+ const getPairs = (base, quote)=>{
+ return web3Client.request(`solana://675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8/getProgramAccounts`, {
+ params: { filters: [
+ { dataSize: AMM_LAYOUT.span },
+ { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6 (Swap)
+ { memcmp: { offset: 400, bytes: base }},
+ { memcmp: { offset: 432, bytes: quote }},
+ ]},
+ api: AMM_LAYOUT,
+ cache: 86400, // 24h,
+ cacheKey: ['raydium', base.toString(), quote.toString()].join('-')
+ })
+ };
+
+ const getPairsWithPrice$3 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ let accounts = await getPairs(tokenIn, tokenOut);
+
+ if(accounts.length == 0) {
+ accounts = await getPairs(tokenOut, tokenIn);
+ }
+
+ const pairs = await Promise.all(accounts.map(async(account)=>{
+
+ const baseMint = account.data.baseMint.toString();
+ const quoteMint = account.data.quoteMint.toString();
+
+ const balances = await Promise.all([
+ web3Client.request(`solana://${account.data.baseVault.toString()}/getTokenAccountBalance`, { cache: 5 }),
+ web3Client.request(`solana://${account.data.quoteVault.toString()}/getTokenAccountBalance`, { cache: 5 })
+ ]);
+ const baseReserve = (_optionalChain$4([balances, 'access', _ => _[0], 'optionalAccess', _2 => _2.value, 'optionalAccess', _3 => _3.amount]) ? new solanaWeb3_js.BN(_optionalChain$4([balances, 'access', _4 => _4[0], 'optionalAccess', _5 => _5.value, 'optionalAccess', _6 => _6.amount])) : new solanaWeb3_js.BN(0)).sub(account.data.baseNeedTakePnl);
+ const quoteReserve = (_optionalChain$4([balances, 'access', _7 => _7[1], 'optionalAccess', _8 => _8.value, 'optionalAccess', _9 => _9.amount]) ? new solanaWeb3_js.BN(_optionalChain$4([balances, 'access', _10 => _10[1], 'optionalAccess', _11 => _11.value, 'optionalAccess', _12 => _12.amount])) : new solanaWeb3_js.BN(0)).sub(account.data.quoteNeedTakePnl);
+
+ if(baseMint === Blockchains__default['default'].solana.wrapped.address) {
+ if(baseReserve.lt(new solanaWeb3_js.BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (quoteMint === Blockchains__default['default'].solana.wrapped.address) {
+ if(quoteReserve.lt(new solanaWeb3_js.BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (Blockchains__default['default'].solana.stables.usd.includes(baseMint)) {
+ if((parseFloat(baseReserve.toString()) / 10 ** account.data.baseDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ } else if (Blockchains__default['default'].solana.stables.usd.includes(quoteMint)) {
+ if((parseFloat(quoteReserve.toString()) / 10 ** account.data.quoteDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ }
+
+ const reserves = [baseReserve, quoteReserve];
+
+ if(tokenOut === baseMint) {
+ reserves.reverse();
+ }
+
+ const [reserveIn, reserveOut] = reserves;
+
+ let price;
+ if(amountOut || amountOutMin) { // compute amountIn
+
+ new solanaWeb3_js.BN(0);
+ let amountOutRaw = new solanaWeb3_js.BN((amountOut || amountOutMin).toString());
+
+ if (amountOutRaw.gt(reserveOut)) {
+ amountOutRaw = reserveOut.sub(new solanaWeb3_js.BN(1));
+ }
+
+ const denominator = reserveOut.sub(amountOutRaw);
+ const amountInWithoutFee = reserveIn.mul(amountOutRaw).div(denominator);
+
+ price = amountInWithoutFee
+ .mul(LIQUIDITY_FEES_DENOMINATOR)
+ .div(LIQUIDITY_FEES_DENOMINATOR.sub(LIQUIDITY_FEES_NUMERATOR))
+ .toString();
+
+ } else { // compute amountOut
+
+ new solanaWeb3_js.BN(0);
+ const amountInRaw = new solanaWeb3_js.BN((amountIn || amountInMin).toString());
+ const feeRaw = BNDivCeil(amountInRaw.mul(LIQUIDITY_FEES_NUMERATOR), LIQUIDITY_FEES_DENOMINATOR);
+
+ const amountInWithFee = amountInRaw.sub(feeRaw);
+ const denominator = reserveIn.add(amountInWithFee);
+
+ price = reserveOut.mul(amountInWithFee).div(denominator).toString();
+ }
+
+ return {
+ publicKey: account.pubkey.toString(),
+ baseMint,
+ quoteMint,
+ price,
+ data: account.data
+ }
+
+ }));
+
+ return pairs.filter(Boolean)
+ };
+
+ const getPairsWithPrice$2 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ };
+
+ const getPairsWithPrice$1 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ };
+
+ const getParisWithPriceForAllTypes = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ return Promise.all([
+ getPairsWithPrice$3({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$2({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$1({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ ]).then((pairsAMM, pairsCPAMM, pairsCLMNN)=>{
+ return [
+ (pairsAMM || []).filter(Boolean).flat(),
+ (pairsCPAMM || []).filter(Boolean).flat(),
+ (pairsCLMNN || []).filter(Boolean).flat()
+ ].flat()
+ })
+ };
+
+ const getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ try {
+ return await getParisWithPriceForAllTypes({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })
+ } catch (e) {
+ return []
+ }
+ };
+
+ let getHighestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).gt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+ };
+
+ let getLowestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).lt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+ };
+
+ let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+
+ if(!pairs || pairs.length === 0) { return }
+
+ let bestPair;
+
+ if(amountIn || amountInMax) {
+ bestPair = getHighestPrice(pairs);
+ } else { // amount out
+ bestPair = getLowestPrice(pairs);
+ }
+
+ return bestPair
+ };
+
+ function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+ const blockchain$1 = Blockchains__default['default'].solana;
+
+ // Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
+ //
+ // We keep 11111111111111111111111111111111 internally
+ // to be able to differentiate between SOL<>Token and WSOL<>Token swaps
+ // as they are not the same!
+ //
+ let getExchangePath$3 = ({ path }) => {
+ if(!path) { return }
+ let exchangePath = path.map((token, index) => {
+ if (
+ token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
+ path[index-1] != blockchain$1.wrapped.address
+ ) {
+ return blockchain$1.wrapped.address
+ } else {
+ return token
+ }
+ });
+
+ if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ exchangePath.splice(0, 1);
+ } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ exchangePath.splice(exchangePath.length-1, 1);
+ }
+
+ return exchangePath
+ };
+
+ let pathExists$4 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ if(path.length == 1) { return false }
+ path = getExchangePath$3({ path });
+ if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ return true
+ } else {
+ return false
+ }
+ };
+
+ let findPath$4 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ if(
+ [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ ) { return { path: undefined, exchangePath: undefined } }
+
+ let path, stablesIn, stablesOut, stable;
+
+ if (await pathExists$4({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ // direct path
+ path = [tokenIn, tokenOut];
+ } else if (
+ tokenIn != blockchain$1.wrapped.address &&
+ tokenIn != blockchain$1.currency.address &&
+ await pathExists$4({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$1.wrapped.address &&
+ tokenOut != blockchain$1.currency.address &&
+ await pathExists$4({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ ) {
+ // path via blockchain.wrapped.address
+ path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ } else if (
+ !blockchain$1.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$1.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists$4({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ (stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
+ ) {
+ // path via TOKEN_IN <> STABLE <> TOKEN_OUT
+ path = [tokenIn, stable, tokenOut];
+ }
+
+ // Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
+ // because that actually reflects how things are routed in reality:
+ if(_optionalChain$3([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
+ path.splice(1, 0, blockchain$1.wrapped.address);
+ } else if(_optionalChain$3([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
+ path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ }
+ return { path, exchangePath: getExchangePath$3({ path }) }
+ };
+
+ let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+
+ let amounts = [ethers.ethers.BigNumber.from(amountIn || amountInMax)];
+
+ let bestPair = await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts
+ };
+
+ let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+
+ path = path.slice().reverse();
+ let amounts = [ethers.ethers.BigNumber.from(amountOut || amountOutMin)];
+
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts.slice().reverse()
+ };
+
+ let getAmounts$4 = async ({
+ path,
+ tokenIn,
+ tokenOut,
+ amountOut,
+ amountIn,
+ amountInMax,
+ amountOutMin
+ }) => {
+ path = getExchangePath$3({ path });
+ let amounts;
+ if (amountOut) {
+ amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if (amountIn) {
+ amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ } else if(amountOutMin) {
+ amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if(amountInMax) {
+ amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ }
+ return {
+ amountOut: (amountOut || amountOutMin),
+ amountIn: (amountIn || amountInMax),
+ amountInMax: (amountInMax || amountIn),
+ amountOutMin: (amountOutMin || amountOut),
+ amounts
+ }
+ };
+
+ const blockchain = Blockchains__default['default'].solana;
+
+ const getTransaction$4 = async({
+ path,
+ amountIn,
+ amountInMax,
+ amountOut,
+ amountOutMin,
+ amounts,
+ amountInInput,
+ amountOutInput,
+ amountInMaxInput,
+ amountOutMinInput,
+ account
+ })=>{
+ let transaction = { blockchain: 'solana' };
+ let instructions = [];
+
+ const exchangePath = getExchangePath$3({ path });
+ if(exchangePath.length > 3) { throw 'Raydium can only handle fixed paths with a max length of 3 (2 pools)!' }
+ const tokenIn = exchangePath[0];
+ const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
+ const tokenOut = exchangePath[exchangePath.length-1];
+
+ let pairs;
+ if(exchangePath.length == 2) {
+ pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ } else {
+ if(amountInInput || amountInMaxInput) {
+ pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ } else { // originally amountOut
+ pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ }
+ }
+
+ let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let wrappedAccount;
+ const provider = await web3Client.getProvider('solana');
+
+ if(startsWrapped || endsUnwrapped) {
+ const rent = await provider.getMinimumBalanceForRentExemption(Token__default['default'].solana.TOKEN_LAYOUT.span);
+ const keypair = solanaWeb3_js.Keypair.generate();
+ wrappedAccount = keypair.publicKey.toString();
+ const lamports = startsWrapped ? new solanaWeb3_js.BN(amountIn.toString()).add(new solanaWeb3_js.BN(rent)) : new solanaWeb3_js.BN(rent);
+ let createAccountInstruction = solanaWeb3_js.SystemProgram.createAccount({
+ fromPubkey: new solanaWeb3_js.PublicKey(account),
+ newAccountPubkey: new solanaWeb3_js.PublicKey(wrappedAccount),
+ programId: new solanaWeb3_js.PublicKey(Token__default['default'].solana.TOKEN_PROGRAM),
+ space: Token__default['default'].solana.TOKEN_LAYOUT.span,
+ lamports
+ });
+ createAccountInstruction.signers = [keypair];
+ instructions.push(createAccountInstruction);
+ instructions.push(
+ Token__default['default'].solana.initializeAccountInstruction({
+ account: wrappedAccount,
+ token: blockchain.wrapped.address,
+ owner: account
+ })
+ );
+ }
+
+ if(pairs.length === 1) { // single hop
+ const tokenAccountIn = startsWrapped ? new solanaWeb3_js.PublicKey(wrappedAccount) : new solanaWeb3_js.PublicKey(await Token__default['default'].solana.findProgramAddress({ owner: account, token: tokenIn }));
+ const tokenAccountOut = endsUnwrapped ? new solanaWeb3_js.PublicKey(wrappedAccount) : new solanaWeb3_js.PublicKey(await Token__default['default'].solana.findProgramAddress({ owner: account, token: tokenOut }));
+ const pool = pairs[0];
+ await web3Client.request(`solana://${pool.data.marketId}/getAccountInfo`, { api: MARKET_LAYOUT });
+
+ let LAYOUT, data;
+ LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.u8('instruction'),
+ solanaWeb3_js.u64('amountIn'),
+ solanaWeb3_js.u64('minAmountOut')
+ ]);
+ data = solanaWeb3_js.Buffer.alloc(LAYOUT.span);
+ LAYOUT.encode(
+ {
+ instruction: 9,
+ amountIn: new solanaWeb3_js.BN((amountIn || amountInMax).toString()),
+ minAmountOut: new solanaWeb3_js.BN((amountOutMin || amountOut).toString()),
+ },
+ data,
+ );
+
+ // if(!endsUnwrapped) {
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenOut, account: tokenAccountOut })
+ // }
+
+ // let keys = [
+ // // token_program
+ // { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // // amm
+ // { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // // amm authority
+ // { pubkey: await getAssociatedAuthority(new PublicKey(pool.publicKey)), isWritable: false, isSigner: false },
+ // // amm openOrders
+ // { pubkey: new PublicKey(pool.data.openOrders), isWritable: true, isSigner: false },
+ // // amm baseVault
+ // { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // // amm quoteVault
+ // { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // // openbook marketProgramId
+ // { pubkey: new PublicKey(pool.data.marketProgramId), isWritable: false, isSigner: false },
+ // // openbook marketId
+ // { pubkey: new PublicKey(pool.data.marketId), isWritable: true, isSigner: false },
+ // // openbook marketBids
+ // { pubkey: market.bids, isWritable: true, isSigner: false },
+ // // openbook marketAsks
+ // { pubkey: market.asks, isWritable: true, isSigner: false },
+ // // openbook eventQueue
+ // { pubkey: market.eventQueue, isWritable: true, isSigner: false },
+ // // openbook baseVault
+ // { pubkey: market.baseVault, isWritable: true, isSigner: false },
+ // // openbook quoteVault
+ // { pubkey: market.quoteVault, isWritable: true, isSigner: false },
+ // // openbook marketAuthority
+ // { pubkey: await getAssociatedMarketAuthority(pool.data.marketProgramId, pool.data.marketId), isWritable: false, isSigner: false },
+ // // user tokenAccountIn
+ // { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // // user tokenAccountOut
+ // { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // // user owner
+ // { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ // ]
+
+ let keys = [
+ // token_program
+ { pubkey: new solanaWeb3_js.PublicKey(Token__default['default'].solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // amm
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm authority
+ { pubkey: new solanaWeb3_js.PublicKey('5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1'), isWritable: false, isSigner: false },
+ // amm openOrders
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm baseVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // amm quoteVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // openbook marketProgramId
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: false, isSigner: false },
+ // openbook marketId
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketBids
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAsks
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook eventQueue
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook baseVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook quoteVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAuthority
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // user tokenAccountIn
+ { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // user tokenAccountOut
+ { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // user owner
+ { pubkey: new solanaWeb3_js.PublicKey(account), isWritable: true, isSigner: true }
+ ];
+
+ console.log('keys', JSON.stringify(keys));
+
+ instructions.push(
+ new solanaWeb3_js.TransactionInstruction({
+ programId: new solanaWeb3_js.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'),
+ keys,
+ data,
+ })
+ );
+ } else if (pairs.length === 2) ;
+
+ if(startsWrapped || endsUnwrapped) {
+ instructions.push(
+ Token__default['default'].solana.closeAccountInstruction({
+ account: wrappedAccount,
+ owner: account
+ })
+ );
+ }
+
+ // await debug(instructions, provider)
+
+ transaction.instructions = instructions;
+ return transaction
+ };
+
+ var Raydium = {
+ findPath: findPath$4,
+ pathExists: pathExists$4,
+ getAmounts: getAmounts$4,
+ getTransaction: getTransaction$4,
+ AMM_LAYOUT,
+ CPAMM_LAYOUT,
+ CLMM_LAYOUT,
+ MARKET_LAYOUT,
+ };
+
+ // // AMM
+ // let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_amm.address}/getProgramAccounts`, {
+ // params: { filters: [
+ // { dataSize: Web3Exchanges.raydium.solana.router_amm.api.span },
+ // { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6
+ // { memcmp: { offset: 400, bytes: "So11111111111111111111111111111111111111112" }},
+ // { memcmp: { offset: 432, bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }},
+ // ]},
+ // api: Web3Exchanges.raydium.solana.router_amm.api,
+ // })
+ // console.log(accounts)
+
+
+ // // CPAMM
+ // let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_cpamm.address}/getProgramAccounts`, {
+ // params: { filters: [
+ // { dataSize: Web3Exchanges.raydium.solana.router_cpamm.api.span },
+ // { memcmp: { offset: 168, bytes: "So11111111111111111111111111111111111111112" }},
+ // { memcmp: { offset: 200, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+ // ]},
+ // api: Web3Exchanges.raydium.solana.router_cpamm.api,
+ // })
+ // console.log(accounts)
+
+
+ // // CLMM
+ // let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_clmm.address}/getProgramAccounts`, {
+ // params: { filters: [
+ // { dataSize: Web3Exchanges.raydium.solana.router_clmm.api.span },
+ // { memcmp: { offset: 73, bytes: "So11111111111111111111111111111111111111112" }},
+ // { memcmp: { offset: 105, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+ // ]},
+ // api: Web3Exchanges.raydium.solana.router_clmm.api,
+ // })
+ // console.log(accounts)
+
+ const exchange$g = {
+
+ name: 'raydium',
+ label: 'Raydium',
+ logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjMzIiB2aWV3Qm94PSIwIDAgMjkgMzMiIHdpZHRoPSIyOSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjI4LjMxNjgiIHgyPSItMS43MzMzNiIgeTE9IjguMTkxNjIiIHkyPSIyMC4yMDg2Ij48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNjMjAwZmIiLz48c3RvcCBvZmZzZXQ9Ii40ODk2NTgiIHN0b3AtY29sb3I9IiMzNzcyZmYiLz48c3RvcCBvZmZzZXQ9Ii40ODk3NTgiIHN0b3AtY29sb3I9IiMzNzczZmUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM1YWM0YmUiLz48L2xpbmVhckdyYWRpZW50PjxnIGZpbGw9InVybCgjYSkiPjxwYXRoIGQ9Im0yNi44NjI1IDEyLjI4MXYxMS40MTA0bC0xMi42OTE2IDcuMzI2MS0xMi42OTg1OS03LjMyNjF2LTE0LjY1OTM3bDEyLjY5ODU5LTcuMzMzMjIgOS43NTQxIDUuNjM0NDEgMS40NzIzLS44NDk0MS0xMS4yMjY0LTYuNDgzODEtMTQuMTcwOSA4LjE4MjYydjE2LjM1ODE4bDE0LjE3MDkgOC4xODI2IDE0LjE3MS04LjE4MjZ2LTEzLjEwOTJ6Ii8+PHBhdGggZD0ibTEwLjYxNzYgMjMuNjk4NWgtMi4xMjM1M3YtNy4xMjA5aDcuMDc4NDNjLjY2OTctLjAwNzQgMS4zMDk1LS4yNzgyIDEuNzgxMS0uNzUzOC40NzE2LS40NzU1LjczNy0xLjExNzYuNzM4OC0xLjc4NzQuMDAzOC0uMzMxMS0uMDYwMS0uNjU5Ni0uMTg3OS0uOTY1MS0uMTI3OS0uMzA1Ni0uMzE2OC0uNTgxNy0uNTU1NC0uODExNS0uMjMwOC0uMjM3Mi0uNTA3MS0uNDI1My0uODEyNC0uNTUzLS4zMDUzLS4xMjc4LS42MzMzLS4xOTI1LS45NjQyLS4xOTAzaC03LjA3ODQzdi0yLjE2NTk1aDcuMDg1NDNjMS4yNDA1LjAwNzQzIDIuNDI4MS41MDM1MSAzLjMwNTMgMS4zODA2NS44NzcxLjg3NzIgMS4zNzMyIDIuMDY0OCAxLjM4MDYgMy4zMDUyLjAwNzYuOTQ5Ni0uMjgxOSAxLjg3NzctLjgyODEgMi42NTQ0LS41MDI3Ljc0MzItMS4yMTExIDEuMzIzNy0yLjAzODYgMS42NzA1LS44MTk0LjI1OTktMS42NzQ1LjM4ODktMi41MzQxLjM4MjNoLTQuMjQ3eiIvPjxwYXRoIGQ9Im0yMC4yMTU5IDIzLjUyMTVoLTIuNDc3NWwtMS45MTExLTMuMzMzOWMuNzU2MS0uMDQ2MyAxLjUwMTktLjE5ODggMi4yMTU1LS40NTN6Ii8+PHBhdGggZD0ibTI1LjM4MzEgOS45MDk3NSAxLjQ2NTIuODE0MDUgMS40NjUzLS44MTQwNXYtMS43MjAwNWwtMS40NjUzLS44NDk0MS0xLjQ2NTIuODQ5NDF6Ii8+PC9nPjwvc3ZnPg==',
+ protocol: 'raydium',
+
+ slippage: true,
+
+ blockchains: ['solana'],
+
+ solana: {
+
+ router_amm: {
+ address: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
+ api: Raydium.AMM_LAYOUT,
+ },
+
+ router_cpamm: {
+ address: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C',
+ api: Raydium.CPAMM_LAYOUT
+ },
+
+ router_clmm: {
+ address: 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK',
+ api: Raydium.CLMM_LAYOUT
+ },
+ }
+ };
+
+ var raydium = (scope)=>{
+
return new Exchange(
Object.assign(exchange$g, {
scope,
- findPath: (args)=>Orca.findPath({ ...args, exchange: exchange$g }),
- pathExists: (args)=>Orca.pathExists({ ...args, exchange: exchange$g }),
- getAmounts: (args)=>Orca.getAmounts({ ...args, exchange: exchange$g }),
+ findPath: (args)=>Raydium.findPath({ ...args, exchange: exchange$g }),
+ pathExists: (args)=>Raydium.pathExists({ ...args, exchange: exchange$g }),
+ getAmounts: (args)=>Raydium.getAmounts({ ...args, exchange: exchange$g }),
getPrep: (args)=>{},
- getTransaction: (args)=>Orca.getTransaction({ ...args, exchange: exchange$g }),
+ getTransaction: (args)=>Raydium.getTransaction({ ...args, exchange: exchange$g }),
})
)
};
@@ -4817,6 +5626,7 @@
const exchanges = [
orca(),
+ raydium(),
uniswap_v3(),
pancakeswap_v3(),
uniswap_v2(),
@@ -4863,6 +5673,7 @@
exchanges.solana = [
orca('solana'),
+ raydium('solana'),
];
exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchange; });
diff --git a/dist/umd/index.solana.js b/dist/umd/index.solana.js
index 0a4dbff..b59b6c3 100644
--- a/dist/umd/index.solana.js
+++ b/dist/umd/index.solana.js
@@ -10,7 +10,7 @@
var Blockchains__default = /*#__PURE__*/_interopDefaultLegacy(Blockchains);
var Decimal__default = /*#__PURE__*/_interopDefaultLegacy(Decimal);
- function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
+ function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }class Route {
constructor({
blockchain,
tokenIn,
@@ -36,10 +36,10 @@
this.decimalsOut = decimalsOut;
this.path = path;
this.pools = pools;
- this.amountIn = _optionalChain$1([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
- this.amountOutMin = _optionalChain$1([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
- this.amountOut = _optionalChain$1([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
- this.amountInMax = _optionalChain$1([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
+ this.amountIn = _optionalChain$3([amountIn, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]);
+ this.amountOutMin = _optionalChain$3([amountOutMin, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]);
+ this.amountOut = _optionalChain$3([amountOut, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]);
+ this.amountInMax = _optionalChain$3([amountInMax, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]);
this.exchange = exchange;
this.getPrep = getPrep;
this.getTransaction = getTransaction;
@@ -313,7 +313,10 @@
let amounts; // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch (e) { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
@@ -1592,7 +1595,7 @@
return accounts
};
- let getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ let getPairsWithPrice$4 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
try {
let accounts = await getAccounts(tokenIn, tokenOut);
if(accounts.length === 0) { accounts = await getAccounts(tokenOut, tokenIn); }
@@ -1619,32 +1622,31 @@
}
};
- let getHighestPrice = (pairs)=>{
+ let getHighestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).gt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
- let getLowestPrice = (pairs)=>{
+ let getLowestPrice$1 = (pairs)=>{
return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).lt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
};
- let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
- const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+ let getBestPair$1 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice$4({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
if(!pairs || pairs.length === 0) { return }
let bestPair;
if(amountIn || amountInMax) {
- bestPair = getHighestPrice(pairs);
+ bestPair = getHighestPrice$1(pairs);
} else { // amount out
- bestPair = getLowestPrice(pairs);
+ bestPair = getLowestPrice$1(pairs);
}
-
return bestPair
};
- function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
- const blockchain$1 = Blockchains__default['default'].solana;
+ function _optionalChain$2(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+ const blockchain$3 = Blockchains__default['default'].solana;
// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
//
@@ -1652,64 +1654,64 @@
// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
// as they are not the same!
//
- let getExchangePath = ({ path }) => {
+ let getExchangePath$1 = ({ path }) => {
if(!path) { return }
let exchangePath = path.map((token, index) => {
if (
- token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
- path[index-1] != blockchain$1.wrapped.address
+ token === blockchain$3.currency.address && path[index+1] != blockchain$3.wrapped.address &&
+ path[index-1] != blockchain$3.wrapped.address
) {
- return blockchain$1.wrapped.address
+ return blockchain$3.wrapped.address
} else {
return token
}
});
- if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ if(exchangePath[0] == blockchain$3.currency.address && exchangePath[1] == blockchain$3.wrapped.address) {
exchangePath.splice(0, 1);
- } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ } else if(exchangePath[exchangePath.length-1] == blockchain$3.currency.address && exchangePath[exchangePath.length-2] == blockchain$3.wrapped.address) {
exchangePath.splice(exchangePath.length-1, 1);
}
return exchangePath
};
- let pathExists = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ let pathExists$1 = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
if(path.length == 1) { return false }
- path = getExchangePath({ path });
- if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ path = getExchangePath$1({ path });
+ if((await getPairsWithPrice$4({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
return true
} else {
return false
}
};
- let findPath = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ let findPath$1 = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
if(
- [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
- [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ [tokenIn, tokenOut].includes(blockchain$3.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$3.wrapped.address)
) { return { path: undefined, exchangePath: undefined } }
let path, stablesIn, stablesOut, stable;
- if (await pathExists({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ if (await pathExists$1({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
// direct path
path = [tokenIn, tokenOut];
} else if (
- tokenIn != blockchain$1.wrapped.address &&
- tokenIn != blockchain$1.currency.address &&
- await pathExists({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
- tokenOut != blockchain$1.wrapped.address &&
- tokenOut != blockchain$1.currency.address &&
- await pathExists({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ tokenIn != blockchain$3.wrapped.address &&
+ tokenIn != blockchain$3.currency.address &&
+ await pathExists$1({ path: [tokenIn, blockchain$3.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$3.wrapped.address &&
+ tokenOut != blockchain$3.currency.address &&
+ await pathExists$1({ path: [tokenOut, blockchain$3.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
) {
// path via blockchain.wrapped.address
- path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ path = [tokenIn, blockchain$3.wrapped.address, tokenOut];
} else if (
- !blockchain$1.stables.usd.includes(tokenIn) &&
- (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
- !blockchain$1.stables.usd.includes(tokenOut) &&
- (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$1({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$3.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$3.stables.usd.map(async(stable)=>await pathExists$1({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
(stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
) {
// path via TOKEN_IN <> STABLE <> TOKEN_OUT
@@ -1718,22 +1720,26 @@
// Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
// because that actually reflects how things are routed in reality:
- if(_optionalChain([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
- path.splice(1, 0, blockchain$1.wrapped.address);
- } else if(_optionalChain([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
- path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ if(_optionalChain$2([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$3.currency.address) {
+ path.splice(1, 0, blockchain$3.wrapped.address);
+ } else if(_optionalChain$2([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$3.currency.address) {
+ path.splice(path.length-1, 0, blockchain$3.wrapped.address);
}
- return { path, exchangePath: getExchangePath({ path }) }
+ return { path, exchangePath: getExchangePath$1({ path }) }
};
- let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+ let getAmountsOut$1 = async ({ path, amountIn, amountInMax }) => {
let amounts = [ethers.ethers.BigNumber.from(amountIn || amountInMax)];
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -1741,15 +1747,19 @@
return amounts
};
- let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+ let getAmountsIn$1 = async({ path, amountOut, amountOutMin }) => {
path = path.slice().reverse();
let amounts = [ethers.ethers.BigNumber.from(amountOut || amountOutMin)];
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
if (path.length === 3) {
- amounts.push(ethers.ethers.BigNumber.from((await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })).price));
+ let bestPair = await getBestPair$1({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
}
if(amounts.length != path.length) { return }
@@ -1757,7 +1767,7 @@
return amounts.slice().reverse()
};
- let getAmounts = async ({
+ let getAmounts$1 = async ({
path,
tokenIn,
tokenOut,
@@ -1766,10 +1776,10 @@
amountInMax,
amountOutMin
}) => {
- path = getExchangePath({ path });
+ path = getExchangePath$1({ path });
let amounts;
if (amountOut) {
- amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOut, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -1777,7 +1787,7 @@
amountInMax = amountIn;
}
} else if (amountIn) {
- amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountIn, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -1785,7 +1795,7 @@
amountOutMin = amountOut;
}
} else if(amountOutMin) {
- amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amounts = await getAmountsIn$1({ path, amountOutMin, tokenIn, tokenOut });
amountIn = amounts ? amounts[0] : undefined;
if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
return {}
@@ -1793,7 +1803,7 @@
amountInMax = amountIn;
}
} else if(amountInMax) {
- amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amounts = await getAmountsOut$1({ path, amountInMax, tokenIn, tokenOut });
amountOut = amounts ? amounts[amounts.length-1] : undefined;
if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
return {}
@@ -1810,7 +1820,7 @@
}
};
- const blockchain = Blockchains__default['default'].solana;
+ const blockchain$2 = Blockchains__default['default'].solana;
const SWAP_INSTRUCTION = new solanaWeb3_js.BN("14449647541112719096");
const TWO_HOP_SWAP_INSTRUCTION = new solanaWeb3_js.BN("16635068063392030915");
@@ -2025,7 +2035,7 @@
return data
};
- const getTransaction = async ({
+ const getTransaction$1 = async ({
path,
amountIn,
amountInMax,
@@ -2041,7 +2051,7 @@
let transaction = { blockchain: 'solana' };
let instructions = [];
- const exchangePath = getExchangePath({ path });
+ const exchangePath = getExchangePath$1({ path });
if(exchangePath.length > 3) { throw 'Orca can only handle fixed paths with a max length of 3 (2 pools)!' }
const tokenIn = exchangePath[0];
const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
@@ -2049,19 +2059,19 @@
let pairs;
if(exchangePath.length == 2) {
- pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs = [await getBestPair$1({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
} else {
if(amountInInput || amountInMaxInput) {
- pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
- pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
} else { // originally amountOut
- pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
- pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ pairs = [await getBestPair$1({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair$1({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
}
}
- let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
- let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let startsWrapped = (path[0] === blockchain$2.currency.address && exchangePath[0] === blockchain$2.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain$2.currency.address && exchangePath[exchangePath.length-1] === blockchain$2.wrapped.address);
let wrappedAccount;
const provider = await web3ClientSolana.getProvider('solana');
@@ -2082,7 +2092,7 @@
instructions.push(
Token__default['default'].solana.initializeAccountInstruction({
account: wrappedAccount,
- token: blockchain.wrapped.address,
+ token: blockchain$2.wrapped.address,
owner: account
})
);
@@ -2179,14 +2189,14 @@
};
var Orca = {
- findPath,
- pathExists,
- getAmounts,
- getTransaction,
+ findPath: findPath$1,
+ pathExists: pathExists$1,
+ getAmounts: getAmounts$1,
+ getTransaction: getTransaction$1,
WHIRLPOOL_LAYOUT,
};
- const exchange = {
+ const exchange$1 = {
name: 'orca',
label: 'Orca',
@@ -2207,22 +2217,822 @@
var orca = (scope)=>{
+ return new Exchange(
+
+ Object.assign(exchange$1, {
+ scope,
+
+ findPath: (args)=>Orca.findPath({ ...args, exchange: exchange$1 }),
+ pathExists: (args)=>Orca.pathExists({ ...args, exchange: exchange$1 }),
+ getAmounts: (args)=>Orca.getAmounts({ ...args, exchange: exchange$1 }),
+ getPrep: (args)=>{},
+ getTransaction: (args)=>Orca.getTransaction({ ...args, exchange: exchange$1 }),
+ })
+ )
+ };
+
+ // OpenBook Market
+ const MARKET_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.blob(5),
+ solanaWeb3_js.blob(8), // accountFlagsLayout('accountFlags'),
+ solanaWeb3_js.publicKey('ownAddress'),
+ solanaWeb3_js.u64('vaultSignerNonce'),
+ solanaWeb3_js.publicKey('baseMint'),
+ solanaWeb3_js.publicKey('quoteMint'),
+ solanaWeb3_js.publicKey('baseVault'),
+ solanaWeb3_js.u64('baseDepositsTotal'),
+ solanaWeb3_js.u64('baseFeesAccrued'),
+ solanaWeb3_js.publicKey('quoteVault'),
+ solanaWeb3_js.u64('quoteDepositsTotal'),
+ solanaWeb3_js.u64('quoteFeesAccrued'),
+ solanaWeb3_js.u64('quoteDustThreshold'),
+ solanaWeb3_js.publicKey('requestQueue'),
+ solanaWeb3_js.publicKey('eventQueue'),
+ solanaWeb3_js.publicKey('bids'),
+ solanaWeb3_js.publicKey('asks'),
+ solanaWeb3_js.u64('baseLotSize'),
+ solanaWeb3_js.u64('quoteLotSize'),
+ solanaWeb3_js.u64('feeRateBps'),
+ solanaWeb3_js.u64('referrerRebatesAccrued'),
+ solanaWeb3_js.blob(7),
+ ]);
+
+ // AMM 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
+ const AMM_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.u64('status'),
+ solanaWeb3_js.u64('nonce'),
+ solanaWeb3_js.u64('maxOrder'),
+ solanaWeb3_js.u64('depth'),
+ solanaWeb3_js.u64('baseDecimal'),
+ solanaWeb3_js.u64('quoteDecimal'),
+ solanaWeb3_js.u64('state'),
+ solanaWeb3_js.u64('resetFlag'),
+ solanaWeb3_js.u64('minSize'),
+ solanaWeb3_js.u64('volMaxCutRatio'),
+ solanaWeb3_js.u64('amountWaveRatio'),
+ solanaWeb3_js.u64('baseLotSize'),
+ solanaWeb3_js.u64('quoteLotSize'),
+ solanaWeb3_js.u64('minPriceMultiplier'),
+ solanaWeb3_js.u64('maxPriceMultiplier'),
+ solanaWeb3_js.u64('systemDecimalValue'),
+ solanaWeb3_js.u64('minSeparateNumerator'),
+ solanaWeb3_js.u64('minSeparateDenominator'),
+ solanaWeb3_js.u64('tradeFeeNumerator'),
+ solanaWeb3_js.u64('tradeFeeDenominator'),
+ solanaWeb3_js.u64('pnlNumerator'),
+ solanaWeb3_js.u64('pnlDenominator'),
+ solanaWeb3_js.u64('swapFeeNumerator'),
+ solanaWeb3_js.u64('swapFeeDenominator'),
+ solanaWeb3_js.u64('baseNeedTakePnl'),
+ solanaWeb3_js.u64('quoteNeedTakePnl'),
+ solanaWeb3_js.u64('quoteTotalPnl'),
+ solanaWeb3_js.u64('baseTotalPnl'),
+ solanaWeb3_js.u64('poolOpenTime'),
+ solanaWeb3_js.u64('punishPcAmount'),
+ solanaWeb3_js.u64('punishCoinAmount'),
+ solanaWeb3_js.u64('orderbookToInitTime'),
+ solanaWeb3_js.u128('swapBaseInAmount'),
+ solanaWeb3_js.u128('swapQuoteOutAmount'),
+ solanaWeb3_js.u64('swapBase2QuoteFee'),
+ solanaWeb3_js.u128('swapQuoteInAmount'),
+ solanaWeb3_js.u128('swapBaseOutAmount'),
+ solanaWeb3_js.u64('swapQuote2BaseFee'),
+ // amm vault
+ solanaWeb3_js.publicKey('baseVault'),
+ solanaWeb3_js.publicKey('quoteVault'),
+ // mint
+ solanaWeb3_js.publicKey('baseMint'),
+ solanaWeb3_js.publicKey('quoteMint'),
+ solanaWeb3_js.publicKey('lpMint'),
+ // market
+ solanaWeb3_js.publicKey('openOrders'),
+ solanaWeb3_js.publicKey('marketId'),
+ solanaWeb3_js.publicKey('marketProgramId'),
+ solanaWeb3_js.publicKey('targetOrders'),
+ solanaWeb3_js.publicKey('withdrawQueue'),
+ solanaWeb3_js.publicKey('lpVault'),
+ solanaWeb3_js.publicKey('owner'),
+ // true circulating supply without lock up
+ solanaWeb3_js.u64('lpReserve'),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 3, 'padding'),
+ ]);
+
+ // CP_AMM CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
+ const CPAMM_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.blob(8),
+ solanaWeb3_js.publicKey("configId"),
+ solanaWeb3_js.publicKey("poolCreator"),
+ solanaWeb3_js.publicKey("vaultA"),
+ solanaWeb3_js.publicKey("vaultB"),
+ solanaWeb3_js.publicKey("mintLp"),
+ solanaWeb3_js.publicKey("mintA"),
+ solanaWeb3_js.publicKey("mintB"),
+ solanaWeb3_js.publicKey("mintProgramA"),
+ solanaWeb3_js.publicKey("mintProgramB"),
+ solanaWeb3_js.publicKey("observationId"),
+ solanaWeb3_js.u8("bump"),
+ solanaWeb3_js.u8("status"),
+ solanaWeb3_js.u8("lpDecimals"),
+ solanaWeb3_js.u8("mintDecimalA"),
+ solanaWeb3_js.u8("mintDecimalB"),
+ solanaWeb3_js.u64("lpAmount"),
+ solanaWeb3_js.u64("protocolFeesMintA"),
+ solanaWeb3_js.u64("protocolFeesMintB"),
+ solanaWeb3_js.u64("fundFeesMintA"),
+ solanaWeb3_js.u64("fundFeesMintB"),
+ solanaWeb3_js.u64("openTime"),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 32),
+ ]);
+
+ // CLMM
+
+ const RewardInfo = solanaWeb3_js.struct([
+ solanaWeb3_js.u8("rewardState"),
+ solanaWeb3_js.u64("openTime"),
+ solanaWeb3_js.u64("endTime"),
+ solanaWeb3_js.u64("lastUpdateTime"),
+ solanaWeb3_js.u128("emissionsPerSecondX64"),
+ solanaWeb3_js.u64("rewardTotalEmissioned"),
+ solanaWeb3_js.u64("rewardClaimed"),
+ solanaWeb3_js.publicKey("tokenMint"),
+ solanaWeb3_js.publicKey("tokenVault"),
+ solanaWeb3_js.publicKey("creator"),
+ solanaWeb3_js.u128("rewardGrowthGlobalX64"),
+ ]);
+
+ const CLMM_LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.blob(8),
+ solanaWeb3_js.u8("bump"),
+ solanaWeb3_js.publicKey("ammConfig"),
+ solanaWeb3_js.publicKey("creator"),
+ solanaWeb3_js.publicKey("mintA"),
+ solanaWeb3_js.publicKey("mintB"),
+ solanaWeb3_js.publicKey("vaultA"),
+ solanaWeb3_js.publicKey("vaultB"),
+ solanaWeb3_js.publicKey("observationId"),
+ solanaWeb3_js.u8("mintDecimalsA"),
+ solanaWeb3_js.u8("mintDecimalsB"),
+ solanaWeb3_js.u16("tickSpacing"),
+ solanaWeb3_js.u128("liquidity"),
+ solanaWeb3_js.u128("sqrtPriceX64"),
+ solanaWeb3_js.i32("tickCurrent"),
+ solanaWeb3_js.u32(),
+ solanaWeb3_js.u128("feeGrowthGlobalX64A"),
+ solanaWeb3_js.u128("feeGrowthGlobalX64B"),
+ solanaWeb3_js.u64("protocolFeesTokenA"),
+ solanaWeb3_js.u64("protocolFeesTokenB"),
+ solanaWeb3_js.u128("swapInAmountTokenA"),
+ solanaWeb3_js.u128("swapOutAmountTokenB"),
+ solanaWeb3_js.u128("swapInAmountTokenB"),
+ solanaWeb3_js.u128("swapOutAmountTokenA"),
+ solanaWeb3_js.u8("status"),
+ solanaWeb3_js.seq(solanaWeb3_js.u8(), 7, ""),
+ solanaWeb3_js.seq(RewardInfo, 3, "rewardInfos"),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 16, "tickArrayBitmap"),
+ solanaWeb3_js.u64("totalFeesTokenA"),
+ solanaWeb3_js.u64("totalFeesClaimedTokenA"),
+ solanaWeb3_js.u64("totalFeesTokenB"),
+ solanaWeb3_js.u64("totalFeesClaimedTokenB"),
+ solanaWeb3_js.u64("fundFeesTokenA"),
+ solanaWeb3_js.u64("fundFeesTokenB"),
+ solanaWeb3_js.u64("startTime"),
+ solanaWeb3_js.seq(solanaWeb3_js.u64(), 15 * 4 - 3, "padding"),
+ ]);
+
+ function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+
+ const LIQUIDITY_FEES_NUMERATOR = new solanaWeb3_js.BN(25);
+ const LIQUIDITY_FEES_DENOMINATOR = new solanaWeb3_js.BN(10000);
+
+ const BNDivCeil = (bn1, bn2)=> {
+ const { div, mod } = bn1.divmod(bn2);
+
+ if (mod.gt(new solanaWeb3_js.BN(0))) {
+ return div.add(new solanaWeb3_js.BN(1))
+ } else {
+ return div
+ }
+ };
+
+ const getPairs = (base, quote)=>{
+ return web3ClientSolana.request(`solana://675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8/getProgramAccounts`, {
+ params: { filters: [
+ { dataSize: AMM_LAYOUT.span },
+ { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6 (Swap)
+ { memcmp: { offset: 400, bytes: base }},
+ { memcmp: { offset: 432, bytes: quote }},
+ ]},
+ api: AMM_LAYOUT,
+ cache: 86400, // 24h,
+ cacheKey: ['raydium', base.toString(), quote.toString()].join('-')
+ })
+ };
+
+ const getPairsWithPrice$3 = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ let accounts = await getPairs(tokenIn, tokenOut);
+
+ if(accounts.length == 0) {
+ accounts = await getPairs(tokenOut, tokenIn);
+ }
+
+ const pairs = await Promise.all(accounts.map(async(account)=>{
+
+ const baseMint = account.data.baseMint.toString();
+ const quoteMint = account.data.quoteMint.toString();
+
+ const balances = await Promise.all([
+ web3ClientSolana.request(`solana://${account.data.baseVault.toString()}/getTokenAccountBalance`, { cache: 5 }),
+ web3ClientSolana.request(`solana://${account.data.quoteVault.toString()}/getTokenAccountBalance`, { cache: 5 })
+ ]);
+ const baseReserve = (_optionalChain$1([balances, 'access', _ => _[0], 'optionalAccess', _2 => _2.value, 'optionalAccess', _3 => _3.amount]) ? new solanaWeb3_js.BN(_optionalChain$1([balances, 'access', _4 => _4[0], 'optionalAccess', _5 => _5.value, 'optionalAccess', _6 => _6.amount])) : new solanaWeb3_js.BN(0)).sub(account.data.baseNeedTakePnl);
+ const quoteReserve = (_optionalChain$1([balances, 'access', _7 => _7[1], 'optionalAccess', _8 => _8.value, 'optionalAccess', _9 => _9.amount]) ? new solanaWeb3_js.BN(_optionalChain$1([balances, 'access', _10 => _10[1], 'optionalAccess', _11 => _11.value, 'optionalAccess', _12 => _12.amount])) : new solanaWeb3_js.BN(0)).sub(account.data.quoteNeedTakePnl);
+
+ if(baseMint === Blockchains__default['default'].solana.wrapped.address) {
+ if(baseReserve.lt(new solanaWeb3_js.BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (quoteMint === Blockchains__default['default'].solana.wrapped.address) {
+ if(quoteReserve.lt(new solanaWeb3_js.BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (Blockchains__default['default'].solana.stables.usd.includes(baseMint)) {
+ if((parseFloat(baseReserve.toString()) / 10 ** account.data.baseDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ } else if (Blockchains__default['default'].solana.stables.usd.includes(quoteMint)) {
+ if((parseFloat(quoteReserve.toString()) / 10 ** account.data.quoteDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ }
+
+ const reserves = [baseReserve, quoteReserve];
+
+ if(tokenOut === baseMint) {
+ reserves.reverse();
+ }
+
+ const [reserveIn, reserveOut] = reserves;
+
+ let price;
+ if(amountOut || amountOutMin) { // compute amountIn
+
+ new solanaWeb3_js.BN(0);
+ let amountOutRaw = new solanaWeb3_js.BN((amountOut || amountOutMin).toString());
+
+ if (amountOutRaw.gt(reserveOut)) {
+ amountOutRaw = reserveOut.sub(new solanaWeb3_js.BN(1));
+ }
+
+ const denominator = reserveOut.sub(amountOutRaw);
+ const amountInWithoutFee = reserveIn.mul(amountOutRaw).div(denominator);
+
+ price = amountInWithoutFee
+ .mul(LIQUIDITY_FEES_DENOMINATOR)
+ .div(LIQUIDITY_FEES_DENOMINATOR.sub(LIQUIDITY_FEES_NUMERATOR))
+ .toString();
+
+ } else { // compute amountOut
+
+ new solanaWeb3_js.BN(0);
+ const amountInRaw = new solanaWeb3_js.BN((amountIn || amountInMin).toString());
+ const feeRaw = BNDivCeil(amountInRaw.mul(LIQUIDITY_FEES_NUMERATOR), LIQUIDITY_FEES_DENOMINATOR);
+
+ const amountInWithFee = amountInRaw.sub(feeRaw);
+ const denominator = reserveIn.add(amountInWithFee);
+
+ price = reserveOut.mul(amountInWithFee).div(denominator).toString();
+ }
+
+ return {
+ publicKey: account.pubkey.toString(),
+ baseMint,
+ quoteMint,
+ price,
+ data: account.data
+ }
+
+ }));
+
+ return pairs.filter(Boolean)
+ };
+
+ const getPairsWithPrice$2 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ };
+
+ const getPairsWithPrice$1 = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ };
+
+ const getParisWithPriceForAllTypes = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ return Promise.all([
+ getPairsWithPrice$3({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$2({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPrice$1({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ ]).then((pairsAMM, pairsCPAMM, pairsCLMNN)=>{
+ return [
+ (pairsAMM || []).filter(Boolean).flat(),
+ (pairsCPAMM || []).filter(Boolean).flat(),
+ (pairsCLMNN || []).filter(Boolean).flat()
+ ].flat()
+ })
+ };
+
+ const getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ try {
+ return await getParisWithPriceForAllTypes({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })
+ } catch (e) {
+ return []
+ }
+ };
+
+ let getHighestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).gt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+ };
+
+ let getLowestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.ethers.BigNumber.from(currentPair.price).lt(ethers.ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+ };
+
+ let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin });
+
+ if(!pairs || pairs.length === 0) { return }
+
+ let bestPair;
+
+ if(amountIn || amountInMax) {
+ bestPair = getHighestPrice(pairs);
+ } else { // amount out
+ bestPair = getLowestPrice(pairs);
+ }
+
+ return bestPair
+ };
+
+ function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+ const blockchain$1 = Blockchains__default['default'].solana;
+
+ // Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
+ //
+ // We keep 11111111111111111111111111111111 internally
+ // to be able to differentiate between SOL<>Token and WSOL<>Token swaps
+ // as they are not the same!
+ //
+ let getExchangePath = ({ path }) => {
+ if(!path) { return }
+ let exchangePath = path.map((token, index) => {
+ if (
+ token === blockchain$1.currency.address && path[index+1] != blockchain$1.wrapped.address &&
+ path[index-1] != blockchain$1.wrapped.address
+ ) {
+ return blockchain$1.wrapped.address
+ } else {
+ return token
+ }
+ });
+
+ if(exchangePath[0] == blockchain$1.currency.address && exchangePath[1] == blockchain$1.wrapped.address) {
+ exchangePath.splice(0, 1);
+ } else if(exchangePath[exchangePath.length-1] == blockchain$1.currency.address && exchangePath[exchangePath.length-2] == blockchain$1.wrapped.address) {
+ exchangePath.splice(exchangePath.length-1, 1);
+ }
+
+ return exchangePath
+ };
+
+ let pathExists = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ if(path.length == 1) { return false }
+ path = getExchangePath({ path });
+ if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ return true
+ } else {
+ return false
+ }
+ };
+
+ let findPath = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ if(
+ [tokenIn, tokenOut].includes(blockchain$1.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain$1.wrapped.address)
+ ) { return { path: undefined, exchangePath: undefined } }
+
+ let path, stablesIn, stablesOut, stable;
+
+ if (await pathExists({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ // direct path
+ path = [tokenIn, tokenOut];
+ } else if (
+ tokenIn != blockchain$1.wrapped.address &&
+ tokenIn != blockchain$1.currency.address &&
+ await pathExists({ path: [tokenIn, blockchain$1.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain$1.wrapped.address &&
+ tokenOut != blockchain$1.currency.address &&
+ await pathExists({ path: [tokenOut, blockchain$1.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ ) {
+ // path via blockchain.wrapped.address
+ path = [tokenIn, blockchain$1.wrapped.address, tokenOut];
+ } else if (
+ !blockchain$1.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain$1.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain$1.stables.usd.map(async(stable)=>await pathExists({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ (stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
+ ) {
+ // path via TOKEN_IN <> STABLE <> TOKEN_OUT
+ path = [tokenIn, stable, tokenOut];
+ }
+
+ // Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
+ // because that actually reflects how things are routed in reality:
+ if(_optionalChain([path, 'optionalAccess', _ => _.length]) && path[0] == blockchain$1.currency.address) {
+ path.splice(1, 0, blockchain$1.wrapped.address);
+ } else if(_optionalChain([path, 'optionalAccess', _2 => _2.length]) && path[path.length-1] == blockchain$1.currency.address) {
+ path.splice(path.length-1, 0, blockchain$1.wrapped.address);
+ }
+ return { path, exchangePath: getExchangePath({ path }) }
+ };
+
+ let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+
+ let amounts = [ethers.ethers.BigNumber.from(amountIn || amountInMax)];
+
+ let bestPair = await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts
+ };
+
+ let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+
+ path = path.slice().reverse();
+ let amounts = [ethers.ethers.BigNumber.from(amountOut || amountOutMin)];
+
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined });
+ if(!bestPair){ return }
+ amounts.push(ethers.ethers.BigNumber.from(bestPair.price));
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts.slice().reverse()
+ };
+
+ let getAmounts = async ({
+ path,
+ tokenIn,
+ tokenOut,
+ amountOut,
+ amountIn,
+ amountInMax,
+ amountOutMin
+ }) => {
+ path = getExchangePath({ path });
+ let amounts;
+ if (amountOut) {
+ amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if (amountIn) {
+ amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ } else if(amountOutMin) {
+ amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut });
+ amountIn = amounts ? amounts[0] : undefined;
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn;
+ }
+ } else if(amountInMax) {
+ amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut });
+ amountOut = amounts ? amounts[amounts.length-1] : undefined;
+ if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut;
+ }
+ }
+ return {
+ amountOut: (amountOut || amountOutMin),
+ amountIn: (amountIn || amountInMax),
+ amountInMax: (amountInMax || amountIn),
+ amountOutMin: (amountOutMin || amountOut),
+ amounts
+ }
+ };
+
+ const blockchain = Blockchains__default['default'].solana;
+
+ const getTransaction = async({
+ path,
+ amountIn,
+ amountInMax,
+ amountOut,
+ amountOutMin,
+ amounts,
+ amountInInput,
+ amountOutInput,
+ amountInMaxInput,
+ amountOutMinInput,
+ account
+ })=>{
+ let transaction = { blockchain: 'solana' };
+ let instructions = [];
+
+ const exchangePath = getExchangePath({ path });
+ if(exchangePath.length > 3) { throw 'Raydium can only handle fixed paths with a max length of 3 (2 pools)!' }
+ const tokenIn = exchangePath[0];
+ const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined;
+ const tokenOut = exchangePath[exchangePath.length-1];
+
+ let pairs;
+ if(exchangePath.length == 2) {
+ pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })];
+ } else {
+ if(amountInInput || amountInMaxInput) {
+ pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })];
+ pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }));
+ } else { // originally amountOut
+ pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })];
+ pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }));
+ }
+ }
+
+ let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address);
+ let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address);
+ let wrappedAccount;
+ const provider = await web3ClientSolana.getProvider('solana');
+
+ if(startsWrapped || endsUnwrapped) {
+ const rent = await provider.getMinimumBalanceForRentExemption(Token__default['default'].solana.TOKEN_LAYOUT.span);
+ const keypair = solanaWeb3_js.Keypair.generate();
+ wrappedAccount = keypair.publicKey.toString();
+ const lamports = startsWrapped ? new solanaWeb3_js.BN(amountIn.toString()).add(new solanaWeb3_js.BN(rent)) : new solanaWeb3_js.BN(rent);
+ let createAccountInstruction = solanaWeb3_js.SystemProgram.createAccount({
+ fromPubkey: new solanaWeb3_js.PublicKey(account),
+ newAccountPubkey: new solanaWeb3_js.PublicKey(wrappedAccount),
+ programId: new solanaWeb3_js.PublicKey(Token__default['default'].solana.TOKEN_PROGRAM),
+ space: Token__default['default'].solana.TOKEN_LAYOUT.span,
+ lamports
+ });
+ createAccountInstruction.signers = [keypair];
+ instructions.push(createAccountInstruction);
+ instructions.push(
+ Token__default['default'].solana.initializeAccountInstruction({
+ account: wrappedAccount,
+ token: blockchain.wrapped.address,
+ owner: account
+ })
+ );
+ }
+
+ if(pairs.length === 1) { // single hop
+ const tokenAccountIn = startsWrapped ? new solanaWeb3_js.PublicKey(wrappedAccount) : new solanaWeb3_js.PublicKey(await Token__default['default'].solana.findProgramAddress({ owner: account, token: tokenIn }));
+ const tokenAccountOut = endsUnwrapped ? new solanaWeb3_js.PublicKey(wrappedAccount) : new solanaWeb3_js.PublicKey(await Token__default['default'].solana.findProgramAddress({ owner: account, token: tokenOut }));
+ const pool = pairs[0];
+ await web3ClientSolana.request(`solana://${pool.data.marketId}/getAccountInfo`, { api: MARKET_LAYOUT });
+
+ let LAYOUT, data;
+ LAYOUT = solanaWeb3_js.struct([
+ solanaWeb3_js.u8('instruction'),
+ solanaWeb3_js.u64('amountIn'),
+ solanaWeb3_js.u64('minAmountOut')
+ ]);
+ data = solanaWeb3_js.Buffer.alloc(LAYOUT.span);
+ LAYOUT.encode(
+ {
+ instruction: 9,
+ amountIn: new solanaWeb3_js.BN((amountIn || amountInMax).toString()),
+ minAmountOut: new solanaWeb3_js.BN((amountOutMin || amountOut).toString()),
+ },
+ data,
+ );
+
+ // if(!endsUnwrapped) {
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenOut, account: tokenAccountOut })
+ // }
+
+ // let keys = [
+ // // token_program
+ // { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // // amm
+ // { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // // amm authority
+ // { pubkey: await getAssociatedAuthority(new PublicKey(pool.publicKey)), isWritable: false, isSigner: false },
+ // // amm openOrders
+ // { pubkey: new PublicKey(pool.data.openOrders), isWritable: true, isSigner: false },
+ // // amm baseVault
+ // { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // // amm quoteVault
+ // { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // // openbook marketProgramId
+ // { pubkey: new PublicKey(pool.data.marketProgramId), isWritable: false, isSigner: false },
+ // // openbook marketId
+ // { pubkey: new PublicKey(pool.data.marketId), isWritable: true, isSigner: false },
+ // // openbook marketBids
+ // { pubkey: market.bids, isWritable: true, isSigner: false },
+ // // openbook marketAsks
+ // { pubkey: market.asks, isWritable: true, isSigner: false },
+ // // openbook eventQueue
+ // { pubkey: market.eventQueue, isWritable: true, isSigner: false },
+ // // openbook baseVault
+ // { pubkey: market.baseVault, isWritable: true, isSigner: false },
+ // // openbook quoteVault
+ // { pubkey: market.quoteVault, isWritable: true, isSigner: false },
+ // // openbook marketAuthority
+ // { pubkey: await getAssociatedMarketAuthority(pool.data.marketProgramId, pool.data.marketId), isWritable: false, isSigner: false },
+ // // user tokenAccountIn
+ // { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // // user tokenAccountOut
+ // { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // // user owner
+ // { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ // ]
+
+ let keys = [
+ // token_program
+ { pubkey: new solanaWeb3_js.PublicKey(Token__default['default'].solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // amm
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm authority
+ { pubkey: new solanaWeb3_js.PublicKey('5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1'), isWritable: false, isSigner: false },
+ // amm openOrders
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm baseVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // amm quoteVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // openbook marketProgramId
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: false, isSigner: false },
+ // openbook marketId
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketBids
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAsks
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook eventQueue
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook baseVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook quoteVault
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAuthority
+ { pubkey: new solanaWeb3_js.PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // user tokenAccountIn
+ { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // user tokenAccountOut
+ { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // user owner
+ { pubkey: new solanaWeb3_js.PublicKey(account), isWritable: true, isSigner: true }
+ ];
+
+ console.log('keys', JSON.stringify(keys));
+
+ instructions.push(
+ new solanaWeb3_js.TransactionInstruction({
+ programId: new solanaWeb3_js.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'),
+ keys,
+ data,
+ })
+ );
+ } else if (pairs.length === 2) ;
+
+ if(startsWrapped || endsUnwrapped) {
+ instructions.push(
+ Token__default['default'].solana.closeAccountInstruction({
+ account: wrappedAccount,
+ owner: account
+ })
+ );
+ }
+
+ // await debug(instructions, provider)
+
+ transaction.instructions = instructions;
+ return transaction
+ };
+
+ var Raydium = {
+ findPath,
+ pathExists,
+ getAmounts,
+ getTransaction,
+ AMM_LAYOUT,
+ CPAMM_LAYOUT,
+ CLMM_LAYOUT,
+ MARKET_LAYOUT,
+ };
+
+ // // AMM
+ // let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_amm.address}/getProgramAccounts`, {
+ // params: { filters: [
+ // { dataSize: Web3Exchanges.raydium.solana.router_amm.api.span },
+ // { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6
+ // { memcmp: { offset: 400, bytes: "So11111111111111111111111111111111111111112" }},
+ // { memcmp: { offset: 432, bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }},
+ // ]},
+ // api: Web3Exchanges.raydium.solana.router_amm.api,
+ // })
+ // console.log(accounts)
+
+
+ // // CPAMM
+ // let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_cpamm.address}/getProgramAccounts`, {
+ // params: { filters: [
+ // { dataSize: Web3Exchanges.raydium.solana.router_cpamm.api.span },
+ // { memcmp: { offset: 168, bytes: "So11111111111111111111111111111111111111112" }},
+ // { memcmp: { offset: 200, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+ // ]},
+ // api: Web3Exchanges.raydium.solana.router_cpamm.api,
+ // })
+ // console.log(accounts)
+
+
+ // // CLMM
+ // let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_clmm.address}/getProgramAccounts`, {
+ // params: { filters: [
+ // { dataSize: Web3Exchanges.raydium.solana.router_clmm.api.span },
+ // { memcmp: { offset: 73, bytes: "So11111111111111111111111111111111111111112" }},
+ // { memcmp: { offset: 105, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+ // ]},
+ // api: Web3Exchanges.raydium.solana.router_clmm.api,
+ // })
+ // console.log(accounts)
+
+ const exchange = {
+
+ name: 'raydium',
+ label: 'Raydium',
+ logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjMzIiB2aWV3Qm94PSIwIDAgMjkgMzMiIHdpZHRoPSIyOSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjI4LjMxNjgiIHgyPSItMS43MzMzNiIgeTE9IjguMTkxNjIiIHkyPSIyMC4yMDg2Ij48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNjMjAwZmIiLz48c3RvcCBvZmZzZXQ9Ii40ODk2NTgiIHN0b3AtY29sb3I9IiMzNzcyZmYiLz48c3RvcCBvZmZzZXQ9Ii40ODk3NTgiIHN0b3AtY29sb3I9IiMzNzczZmUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM1YWM0YmUiLz48L2xpbmVhckdyYWRpZW50PjxnIGZpbGw9InVybCgjYSkiPjxwYXRoIGQ9Im0yNi44NjI1IDEyLjI4MXYxMS40MTA0bC0xMi42OTE2IDcuMzI2MS0xMi42OTg1OS03LjMyNjF2LTE0LjY1OTM3bDEyLjY5ODU5LTcuMzMzMjIgOS43NTQxIDUuNjM0NDEgMS40NzIzLS44NDk0MS0xMS4yMjY0LTYuNDgzODEtMTQuMTcwOSA4LjE4MjYydjE2LjM1ODE4bDE0LjE3MDkgOC4xODI2IDE0LjE3MS04LjE4MjZ2LTEzLjEwOTJ6Ii8+PHBhdGggZD0ibTEwLjYxNzYgMjMuNjk4NWgtMi4xMjM1M3YtNy4xMjA5aDcuMDc4NDNjLjY2OTctLjAwNzQgMS4zMDk1LS4yNzgyIDEuNzgxMS0uNzUzOC40NzE2LS40NzU1LjczNy0xLjExNzYuNzM4OC0xLjc4NzQuMDAzOC0uMzMxMS0uMDYwMS0uNjU5Ni0uMTg3OS0uOTY1MS0uMTI3OS0uMzA1Ni0uMzE2OC0uNTgxNy0uNTU1NC0uODExNS0uMjMwOC0uMjM3Mi0uNTA3MS0uNDI1My0uODEyNC0uNTUzLS4zMDUzLS4xMjc4LS42MzMzLS4xOTI1LS45NjQyLS4xOTAzaC03LjA3ODQzdi0yLjE2NTk1aDcuMDg1NDNjMS4yNDA1LjAwNzQzIDIuNDI4MS41MDM1MSAzLjMwNTMgMS4zODA2NS44NzcxLjg3NzIgMS4zNzMyIDIuMDY0OCAxLjM4MDYgMy4zMDUyLjAwNzYuOTQ5Ni0uMjgxOSAxLjg3NzctLjgyODEgMi42NTQ0LS41MDI3Ljc0MzItMS4yMTExIDEuMzIzNy0yLjAzODYgMS42NzA1LS44MTk0LjI1OTktMS42NzQ1LjM4ODktMi41MzQxLjM4MjNoLTQuMjQ3eiIvPjxwYXRoIGQ9Im0yMC4yMTU5IDIzLjUyMTVoLTIuNDc3NWwtMS45MTExLTMuMzMzOWMuNzU2MS0uMDQ2MyAxLjUwMTktLjE5ODggMi4yMTU1LS40NTN6Ii8+PHBhdGggZD0ibTI1LjM4MzEgOS45MDk3NSAxLjQ2NTIuODE0MDUgMS40NjUzLS44MTQwNXYtMS43MjAwNWwtMS40NjUzLS44NDk0MS0xLjQ2NTIuODQ5NDF6Ii8+PC9nPjwvc3ZnPg==',
+ protocol: 'raydium',
+
+ slippage: true,
+
+ blockchains: ['solana'],
+
+ solana: {
+
+ router_amm: {
+ address: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
+ api: Raydium.AMM_LAYOUT,
+ },
+
+ router_cpamm: {
+ address: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C',
+ api: Raydium.CPAMM_LAYOUT
+ },
+
+ router_clmm: {
+ address: 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK',
+ api: Raydium.CLMM_LAYOUT
+ },
+ }
+ };
+
+ var raydium = (scope)=>{
+
return new Exchange(
Object.assign(exchange, {
scope,
- findPath: (args)=>Orca.findPath({ ...args, exchange }),
- pathExists: (args)=>Orca.pathExists({ ...args, exchange }),
- getAmounts: (args)=>Orca.getAmounts({ ...args, exchange }),
+ findPath: (args)=>Raydium.findPath({ ...args, exchange }),
+ pathExists: (args)=>Raydium.pathExists({ ...args, exchange }),
+ getAmounts: (args)=>Raydium.getAmounts({ ...args, exchange }),
getPrep: (args)=>{},
- getTransaction: (args)=>Orca.getTransaction({ ...args, exchange }),
+ getTransaction: (args)=>Raydium.getTransaction({ ...args, exchange }),
})
)
};
const exchanges = [
orca(),
+ raydium(),
];
exchanges.forEach((exchange)=>{
exchanges[exchange.name] = exchange;
@@ -2230,6 +3040,7 @@
exchanges.solana = [
orca('solana'),
+ raydium('solana'),
];
exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchange; });
diff --git a/examples/raydium.md b/examples/raydium.md
new file mode 100644
index 0000000..6b75da8
--- /dev/null
+++ b/examples/raydium.md
@@ -0,0 +1,20 @@
+## AMM v4 (Legacy)
+
+### 1 Pool
+
+```javascript
+let route = await Web3Exchanges.raydium.route({
+ blockchain: 'solana',
+ tokenIn: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
+ tokenOut: 'HhJpBhRRn4g56VsyLuT8DL5Bv31HkXqsrahTTUCZeZg4',
+ amountOutMin: 0.01
+})
+
+let wallets = await Web3Wallets.getWallets()
+let wallet = wallets[1]
+let account = await wallet.account()
+let transaction = await route.getTransaction({ account })
+
+wallet.sendTransaction(transaction)
+```
+
diff --git a/package.evm.json b/package.evm.json
index 9d312b4..9733e64 100644
--- a/package.evm.json
+++ b/package.evm.json
@@ -1,7 +1,7 @@
{
"name": "@depay/web3-exchanges-evm",
"moduleName": "Web3Exchanges",
- "version": "13.13.1",
+ "version": "13.15.0",
"description": "JavaScript library simplifying decentralized web3 exchange routing for multiple blockchains and exchanges.",
"main": "dist/umd/index.evm.js",
"module": "dist/esm/index.evm.js",
diff --git a/package.json b/package.json
index 3e4053e..f9bb210 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@depay/web3-exchanges",
"moduleName": "Web3Exchanges",
- "version": "13.13.1",
+ "version": "13.15.0",
"description": "JavaScript library simplifying decentralized web3 exchange routing for multiple blockchains and exchanges.",
"main": "dist/umd/index.js",
"module": "dist/esm/index.js",
diff --git a/package.solana.json b/package.solana.json
index a994af3..26e0f10 100644
--- a/package.solana.json
+++ b/package.solana.json
@@ -1,7 +1,7 @@
{
"name": "@depay/web3-exchanges-solana",
"moduleName": "Web3Exchanges",
- "version": "13.13.1",
+ "version": "13.15.0",
"description": "JavaScript library simplifying decentralized web3 exchange routing for multiple blockchains and exchanges.",
"main": "dist/umd/index.solana.js",
"module": "dist/esm/index.solana.js",
diff --git a/src/classes/Exchange.js b/src/classes/Exchange.js
index 9ae7fa5..1edc512 100644
--- a/src/classes/Exchange.js
+++ b/src/classes/Exchange.js
@@ -47,7 +47,10 @@ const route = ({
let amounts // includes intermediary amounts for longer routes
try {
;({ amountIn, amountInMax, amountOut, amountOutMin, amounts } = await getAmounts({ exchange, blockchain, path, pools, tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }));
- } catch { return resolve() }
+ } catch(e) {
+ console.log(e);
+ return resolve()
+ }
if([amountIn, amountInMax, amountOut, amountOutMin].every((amount)=>{ return amount == undefined })) { return resolve() }
if(exchange.slippage && slippage !== false) {
diff --git a/src/exchanges.js b/src/exchanges.js
index 5f330b4..d1cb609 100644
--- a/src/exchanges.js
+++ b/src/exchanges.js
@@ -111,9 +111,11 @@ exchanges.worldchain.forEach((exchange)=>{ exchanges.worldchain[exchange.name] =
/*#elif _SOLANA
import orca from './exchanges/orca'
+import raydium from './exchanges/raydium'
const exchanges = [
orca(),
+ raydium(),
]
exchanges.forEach((exchange)=>{
exchanges[exchange.name] = exchange
@@ -121,6 +123,7 @@ exchanges.forEach((exchange)=>{
exchanges.solana = [
orca('solana'),
+ raydium('solana'),
]
exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchange })
@@ -128,6 +131,7 @@ exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchang
import honeyswap from './exchanges/honeyswap'
import orca from './exchanges/orca'
+import raydium from './exchanges/raydium'
import pancakeswap from './exchanges/pancakeswap'
import pancakeswap_v3 from './exchanges/pancakeswap_v3'
import quickswap from './exchanges/quickswap'
@@ -147,6 +151,7 @@ import wxdai from './exchanges/wxdai'
const exchanges = [
orca(),
+ raydium(),
uniswap_v3(),
pancakeswap_v3(),
uniswap_v2(),
@@ -193,6 +198,7 @@ exchanges.polygon.forEach((exchange)=>{ exchanges.polygon[exchange.name] = excha
exchanges.solana = [
orca('solana'),
+ raydium('solana'),
]
exchanges.solana.forEach((exchange)=>{ exchanges.solana[exchange.name] = exchange })
diff --git a/src/exchanges/raydium.js b/src/exchanges/raydium.js
new file mode 100644
index 0000000..cf1ad5e
--- /dev/null
+++ b/src/exchanges/raydium.js
@@ -0,0 +1,48 @@
+import Exchange from '../classes/Exchange'
+import Raydium from '../platforms/solana/raydium'
+
+const exchange = {
+
+ name: 'raydium',
+ label: 'Raydium',
+ logo: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjMzIiB2aWV3Qm94PSIwIDAgMjkgMzMiIHdpZHRoPSIyOSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGxpbmVhckdyYWRpZW50IGlkPSJhIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjI4LjMxNjgiIHgyPSItMS43MzMzNiIgeTE9IjguMTkxNjIiIHkyPSIyMC4yMDg2Ij48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNjMjAwZmIiLz48c3RvcCBvZmZzZXQ9Ii40ODk2NTgiIHN0b3AtY29sb3I9IiMzNzcyZmYiLz48c3RvcCBvZmZzZXQ9Ii40ODk3NTgiIHN0b3AtY29sb3I9IiMzNzczZmUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM1YWM0YmUiLz48L2xpbmVhckdyYWRpZW50PjxnIGZpbGw9InVybCgjYSkiPjxwYXRoIGQ9Im0yNi44NjI1IDEyLjI4MXYxMS40MTA0bC0xMi42OTE2IDcuMzI2MS0xMi42OTg1OS03LjMyNjF2LTE0LjY1OTM3bDEyLjY5ODU5LTcuMzMzMjIgOS43NTQxIDUuNjM0NDEgMS40NzIzLS44NDk0MS0xMS4yMjY0LTYuNDgzODEtMTQuMTcwOSA4LjE4MjYydjE2LjM1ODE4bDE0LjE3MDkgOC4xODI2IDE0LjE3MS04LjE4MjZ2LTEzLjEwOTJ6Ii8+PHBhdGggZD0ibTEwLjYxNzYgMjMuNjk4NWgtMi4xMjM1M3YtNy4xMjA5aDcuMDc4NDNjLjY2OTctLjAwNzQgMS4zMDk1LS4yNzgyIDEuNzgxMS0uNzUzOC40NzE2LS40NzU1LjczNy0xLjExNzYuNzM4OC0xLjc4NzQuMDAzOC0uMzMxMS0uMDYwMS0uNjU5Ni0uMTg3OS0uOTY1MS0uMTI3OS0uMzA1Ni0uMzE2OC0uNTgxNy0uNTU1NC0uODExNS0uMjMwOC0uMjM3Mi0uNTA3MS0uNDI1My0uODEyNC0uNTUzLS4zMDUzLS4xMjc4LS42MzMzLS4xOTI1LS45NjQyLS4xOTAzaC03LjA3ODQzdi0yLjE2NTk1aDcuMDg1NDNjMS4yNDA1LjAwNzQzIDIuNDI4MS41MDM1MSAzLjMwNTMgMS4zODA2NS44NzcxLjg3NzIgMS4zNzMyIDIuMDY0OCAxLjM4MDYgMy4zMDUyLjAwNzYuOTQ5Ni0uMjgxOSAxLjg3NzctLjgyODEgMi42NTQ0LS41MDI3Ljc0MzItMS4yMTExIDEuMzIzNy0yLjAzODYgMS42NzA1LS44MTk0LjI1OTktMS42NzQ1LjM4ODktMi41MzQxLjM4MjNoLTQuMjQ3eiIvPjxwYXRoIGQ9Im0yMC4yMTU5IDIzLjUyMTVoLTIuNDc3NWwtMS45MTExLTMuMzMzOWMuNzU2MS0uMDQ2MyAxLjUwMTktLjE5ODggMi4yMTU1LS40NTN6Ii8+PHBhdGggZD0ibTI1LjM4MzEgOS45MDk3NSAxLjQ2NTIuODE0MDUgMS40NjUzLS44MTQwNXYtMS43MjAwNWwtMS40NjUzLS44NDk0MS0xLjQ2NTIuODQ5NDF6Ii8+PC9nPjwvc3ZnPg==',
+ protocol: 'raydium',
+
+ slippage: true,
+
+ blockchains: ['solana'],
+
+ solana: {
+
+ router_amm: {
+ address: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
+ api: Raydium.AMM_LAYOUT,
+ },
+
+ router_cpamm: {
+ address: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C',
+ api: Raydium.CPAMM_LAYOUT
+ },
+
+ router_clmm: {
+ address: 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK',
+ api: Raydium.CLMM_LAYOUT
+ },
+ }
+}
+
+export default (scope)=>{
+
+ return new Exchange(
+
+ Object.assign(exchange, {
+ scope,
+
+ findPath: (args)=>Raydium.findPath({ ...args, exchange }),
+ pathExists: (args)=>Raydium.pathExists({ ...args, exchange }),
+ getAmounts: (args)=>Raydium.getAmounts({ ...args, exchange }),
+ getPrep: (args)=>{},
+ getTransaction: (args)=>Raydium.getTransaction({ ...args, exchange }),
+ })
+ )
+}
diff --git a/src/platforms/solana/orca.js b/src/platforms/solana/orca.js
deleted file mode 100644
index e67fb93..0000000
--- a/src/platforms/solana/orca.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { findPath, pathExists } from './orca/path'
-import { getAmounts } from './orca/amounts'
-import { getTransaction } from './orca/transaction'
-import { WHIRLPOOL_LAYOUT } from './orca/layouts'
-
-export default {
- findPath,
- pathExists,
- getAmounts,
- getTransaction,
- WHIRLPOOL_LAYOUT,
-}
diff --git a/src/platforms/solana/orca/amounts.js b/src/platforms/solana/orca/amounts.js
index 81dbb62..1aeff40 100644
--- a/src/platforms/solana/orca/amounts.js
+++ b/src/platforms/solana/orca/amounts.js
@@ -6,10 +6,14 @@ let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
let amounts = [ethers.BigNumber.from(amountIn || amountInMax)]
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })).price))
+ let bestPair = await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
if (path.length === 3) {
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })).price))
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
}
if(amounts.length != path.length) { return }
@@ -22,10 +26,14 @@ let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
path = path.slice().reverse()
let amounts = [ethers.BigNumber.from(amountOut || amountOutMin)]
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })).price))
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
if (path.length === 3) {
- amounts.push(ethers.BigNumber.from((await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })).price))
+ let bestPair = await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
}
if(amounts.length != path.length) { return }
diff --git a/src/platforms/solana/orca/index.js b/src/platforms/solana/orca/index.js
new file mode 100644
index 0000000..344ccfa
--- /dev/null
+++ b/src/platforms/solana/orca/index.js
@@ -0,0 +1,12 @@
+import { findPath, pathExists } from './path'
+import { getAmounts } from './amounts'
+import { getTransaction } from './transaction'
+import { WHIRLPOOL_LAYOUT } from './layouts'
+
+export default {
+ findPath,
+ pathExists,
+ getAmounts,
+ getTransaction,
+ WHIRLPOOL_LAYOUT,
+}
diff --git a/src/platforms/solana/orca/pairs.js b/src/platforms/solana/orca/pairs.js
index b9611d2..aff1e55 100644
--- a/src/platforms/solana/orca/pairs.js
+++ b/src/platforms/solana/orca/pairs.js
@@ -82,7 +82,6 @@ let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, a
} else { // amount out
bestPair = getLowestPrice(pairs)
}
-
return bestPair
}
diff --git a/src/platforms/solana/raydium/amm/pairs.js b/src/platforms/solana/raydium/amm/pairs.js
new file mode 100644
index 0000000..f7e76a7
--- /dev/null
+++ b/src/platforms/solana/raydium/amm/pairs.js
@@ -0,0 +1,136 @@
+/*#if _EVM
+
+/*#elif _SOLANA
+
+import { request } from '@depay/web3-client-solana'
+import { BN } from '@depay/solana-web3.js'
+
+//#else */
+
+import { request } from '@depay/web3-client'
+import { BN } from '@depay/solana-web3.js'
+
+//#endif
+
+import Blockchains from '@depay/web3-blockchains'
+import { AMM_LAYOUT } from '../layouts'
+
+export const LIQUIDITY_FEES_NUMERATOR = new BN(25)
+export const LIQUIDITY_FEES_DENOMINATOR = new BN(10000)
+
+const BNDivCeil = (bn1, bn2)=> {
+ const { div, mod } = bn1.divmod(bn2)
+
+ if (mod.gt(new BN(0))) {
+ return div.add(new BN(1))
+ } else {
+ return div
+ }
+}
+
+const getPairs = (base, quote)=>{
+ return request(`solana://675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8/getProgramAccounts`, {
+ params: { filters: [
+ { dataSize: AMM_LAYOUT.span },
+ { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6 (Swap)
+ { memcmp: { offset: 400, bytes: base }},
+ { memcmp: { offset: 432, bytes: quote }},
+ ]},
+ api: AMM_LAYOUT,
+ cache: 86400, // 24h,
+ cacheKey: ['raydium', base.toString(), quote.toString()].join('-')
+ })
+}
+
+const getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+ let accounts = await getPairs(tokenIn, tokenOut)
+
+ if(accounts.length == 0) {
+ accounts = await getPairs(tokenOut, tokenIn)
+ }
+
+ const pairs = await Promise.all(accounts.map(async(account)=>{
+
+ const baseMint = account.data.baseMint.toString()
+ const quoteMint = account.data.quoteMint.toString()
+
+ const balances = await Promise.all([
+ request(`solana://${account.data.baseVault.toString()}/getTokenAccountBalance`, { cache: 5 }),
+ request(`solana://${account.data.quoteVault.toString()}/getTokenAccountBalance`, { cache: 5 })
+ ])
+ const baseReserve = (balances[0]?.value?.amount ? new BN(balances[0]?.value?.amount) : new BN(0)).sub(account.data.baseNeedTakePnl)
+ const quoteReserve = (balances[1]?.value?.amount ? new BN(balances[1]?.value?.amount) : new BN(0)).sub(account.data.quoteNeedTakePnl)
+
+ if(baseMint === Blockchains.solana.wrapped.address) {
+ if(baseReserve.lt(new BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (quoteMint === Blockchains.solana.wrapped.address) {
+ if(quoteReserve.lt(new BN(50000000))) {
+ return // to little liquidity
+ }
+ } else if (Blockchains.solana.stables.usd.includes(baseMint)) {
+ if((parseFloat(baseReserve.toString()) / 10 ** account.data.baseDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ } else if (Blockchains.solana.stables.usd.includes(quoteMint)) {
+ if((parseFloat(quoteReserve.toString()) / 10 ** account.data.quoteDecimal.toNumber()) < 10000) {
+ return // to little liquidity
+ }
+ }
+
+ const reserves = [baseReserve, quoteReserve]
+
+ if(tokenOut === baseMint) {
+ reserves.reverse()
+ }
+
+ const [reserveIn, reserveOut] = reserves
+
+ let price
+ if(amountOut || amountOutMin) { // compute amountIn
+
+ const amountInRaw = new BN(0)
+ let amountOutRaw = new BN((amountOut || amountOutMin).toString())
+
+ if (amountOutRaw.gt(reserveOut)) {
+ amountOutRaw = reserveOut.sub(new BN(1))
+ }
+
+ const denominator = reserveOut.sub(amountOutRaw)
+ const amountInWithoutFee = reserveIn.mul(amountOutRaw).div(denominator)
+
+ price = amountInWithoutFee
+ .mul(LIQUIDITY_FEES_DENOMINATOR)
+ .div(LIQUIDITY_FEES_DENOMINATOR.sub(LIQUIDITY_FEES_NUMERATOR))
+ .toString()
+
+ } else { // compute amountOut
+
+ const amountOutRaw = new BN(0)
+ const amountInRaw = new BN((amountIn || amountInMin).toString())
+ const feeRaw = BNDivCeil(amountInRaw.mul(LIQUIDITY_FEES_NUMERATOR), LIQUIDITY_FEES_DENOMINATOR)
+
+ const amountInWithFee = amountInRaw.sub(feeRaw)
+ const denominator = reserveIn.add(amountInWithFee)
+
+ price = reserveOut.mul(amountInWithFee).div(denominator).toString()
+ }
+
+ return {
+ publicKey: account.pubkey.toString(),
+ baseMint,
+ quoteMint,
+ price,
+ data: account.data
+ }
+
+ }))
+
+ return pairs.filter(Boolean)
+}
+
+export {
+ getPairsWithPrice
+}
diff --git a/src/platforms/solana/raydium/amounts.js b/src/platforms/solana/raydium/amounts.js
new file mode 100644
index 0000000..1aeff40
--- /dev/null
+++ b/src/platforms/solana/raydium/amounts.js
@@ -0,0 +1,101 @@
+import { ethers } from 'ethers'
+import { getExchangePath } from './path'
+import { getBestPair } from './pairs'
+
+let getAmountsOut = async ({ path, amountIn, amountInMax }) => {
+
+ let amounts = [ethers.BigNumber.from(amountIn || amountInMax)]
+
+ let bestPair = await getBestPair({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[2], amountIn: amountIn ? amounts[1] : undefined, amountInMax: amountInMax ? amounts[1] : undefined })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts
+}
+
+let getAmountsIn = async({ path, amountOut, amountOutMin }) => {
+
+ path = path.slice().reverse()
+ let amounts = [ethers.BigNumber.from(amountOut || amountOutMin)]
+
+ let bestPair = await getBestPair({ tokenIn: path[1], tokenOut: path[0], amountOut, amountOutMin })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
+
+ if (path.length === 3) {
+ let bestPair = await getBestPair({ tokenIn: path[2], tokenOut: path[1], amountOut: amountOut ? amounts[1] : undefined, amountOutMin: amountOutMin ? amounts[1] : undefined })
+ if(!bestPair){ return }
+ amounts.push(ethers.BigNumber.from(bestPair.price))
+ }
+
+ if(amounts.length != path.length) { return }
+
+ return amounts.slice().reverse()
+}
+
+let getAmounts = async ({
+ path,
+ tokenIn,
+ tokenOut,
+ amountOut,
+ amountIn,
+ amountInMax,
+ amountOutMin
+}) => {
+ path = getExchangePath({ path })
+ let amounts
+ if (amountOut) {
+ amounts = await getAmountsIn({ path, amountOut, tokenIn, tokenOut })
+ amountIn = amounts ? amounts[0] : undefined
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn
+ }
+ } else if (amountIn) {
+ amounts = await getAmountsOut({ path, amountIn, tokenIn, tokenOut })
+ amountOut = amounts ? amounts[amounts.length-1] : undefined
+ if (amountOut == undefined || amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut
+ }
+ } else if(amountOutMin) {
+ amounts = await getAmountsIn({ path, amountOutMin, tokenIn, tokenOut })
+ amountIn = amounts ? amounts[0] : undefined
+ if (amountIn == undefined || amountInMax && amountIn.gt(amountInMax)) {
+ return {}
+ } else if (amountInMax === undefined) {
+ amountInMax = amountIn
+ }
+ } else if(amountInMax) {
+ amounts = await getAmountsOut({ path, amountInMax, tokenIn, tokenOut })
+ amountOut = amounts ? amounts[amounts.length-1] : undefined
+ if (amountOut == undefined ||amountOutMin && amountOut.lt(amountOutMin)) {
+ return {}
+ } else if (amountOutMin === undefined) {
+ amountOutMin = amountOut
+ }
+ }
+ return {
+ amountOut: (amountOut || amountOutMin),
+ amountIn: (amountIn || amountInMax),
+ amountInMax: (amountInMax || amountIn),
+ amountOutMin: (amountOutMin || amountOut),
+ amounts
+ }
+}
+
+export {
+ getAmounts,
+ getAmountsIn,
+ getAmountsOut,
+}
diff --git a/src/platforms/solana/raydium/clmm/pairs.js b/src/platforms/solana/raydium/clmm/pairs.js
new file mode 100644
index 0000000..26e573e
--- /dev/null
+++ b/src/platforms/solana/raydium/clmm/pairs.js
@@ -0,0 +1,7 @@
+const getPairsWithPrice = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+}
+
+export {
+ getPairsWithPrice
+}
diff --git a/src/platforms/solana/raydium/cpamm/pairs.js b/src/platforms/solana/raydium/cpamm/pairs.js
new file mode 100644
index 0000000..26e573e
--- /dev/null
+++ b/src/platforms/solana/raydium/cpamm/pairs.js
@@ -0,0 +1,7 @@
+const getPairsWithPrice = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+
+}
+
+export {
+ getPairsWithPrice
+}
diff --git a/src/platforms/solana/raydium/index.js b/src/platforms/solana/raydium/index.js
new file mode 100644
index 0000000..f7766a4
--- /dev/null
+++ b/src/platforms/solana/raydium/index.js
@@ -0,0 +1,51 @@
+import { findPath, pathExists } from './path'
+import { getAmounts } from './amounts'
+import { getTransaction } from './transaction'
+import { AMM_LAYOUT, CPAMM_LAYOUT, CLMM_LAYOUT, MARKET_LAYOUT } from './layouts'
+
+export default {
+ findPath,
+ pathExists,
+ getAmounts,
+ getTransaction,
+ AMM_LAYOUT,
+ CPAMM_LAYOUT,
+ CLMM_LAYOUT,
+ MARKET_LAYOUT,
+}
+
+// // AMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_amm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_amm.api.span },
+// { memcmp: { offset: 0, bytes: [6,0,0] }}, // filters for status 6
+// { memcmp: { offset: 400, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 432, bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_amm.api,
+// })
+// console.log(accounts)
+
+
+// // CPAMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_cpamm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_cpamm.api.span },
+// { memcmp: { offset: 168, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 200, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_cpamm.api,
+// })
+// console.log(accounts)
+
+
+// // CLMM
+// let accounts = await Web3Client.request(`solana://${Web3Exchanges.raydium.solana.router_clmm.address}/getProgramAccounts`, {
+// params: { filters: [
+// { dataSize: Web3Exchanges.raydium.solana.router_clmm.api.span },
+// { memcmp: { offset: 73, bytes: "So11111111111111111111111111111111111111112" }},
+// { memcmp: { offset: 105, bytes: "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv" }},
+// ]},
+// api: Web3Exchanges.raydium.solana.router_clmm.api,
+// })
+// console.log(accounts)
diff --git a/src/platforms/solana/raydium/layouts.js b/src/platforms/solana/raydium/layouts.js
new file mode 100644
index 0000000..5b94fac
--- /dev/null
+++ b/src/platforms/solana/raydium/layouts.js
@@ -0,0 +1,176 @@
+import { blob, bool, struct, u8, u16, i32, u32, u64, i128, u128, publicKey, seq } from '@depay/solana-web3.js'
+
+// OpenBook Market
+const MARKET_LAYOUT = struct([
+ blob(5),
+ blob(8), // accountFlagsLayout('accountFlags'),
+ publicKey('ownAddress'),
+ u64('vaultSignerNonce'),
+ publicKey('baseMint'),
+ publicKey('quoteMint'),
+ publicKey('baseVault'),
+ u64('baseDepositsTotal'),
+ u64('baseFeesAccrued'),
+ publicKey('quoteVault'),
+ u64('quoteDepositsTotal'),
+ u64('quoteFeesAccrued'),
+ u64('quoteDustThreshold'),
+ publicKey('requestQueue'),
+ publicKey('eventQueue'),
+ publicKey('bids'),
+ publicKey('asks'),
+ u64('baseLotSize'),
+ u64('quoteLotSize'),
+ u64('feeRateBps'),
+ u64('referrerRebatesAccrued'),
+ blob(7),
+])
+
+// AMM 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
+const AMM_LAYOUT = struct([
+ u64('status'),
+ u64('nonce'),
+ u64('maxOrder'),
+ u64('depth'),
+ u64('baseDecimal'),
+ u64('quoteDecimal'),
+ u64('state'),
+ u64('resetFlag'),
+ u64('minSize'),
+ u64('volMaxCutRatio'),
+ u64('amountWaveRatio'),
+ u64('baseLotSize'),
+ u64('quoteLotSize'),
+ u64('minPriceMultiplier'),
+ u64('maxPriceMultiplier'),
+ u64('systemDecimalValue'),
+ u64('minSeparateNumerator'),
+ u64('minSeparateDenominator'),
+ u64('tradeFeeNumerator'),
+ u64('tradeFeeDenominator'),
+ u64('pnlNumerator'),
+ u64('pnlDenominator'),
+ u64('swapFeeNumerator'),
+ u64('swapFeeDenominator'),
+ u64('baseNeedTakePnl'),
+ u64('quoteNeedTakePnl'),
+ u64('quoteTotalPnl'),
+ u64('baseTotalPnl'),
+ u64('poolOpenTime'),
+ u64('punishPcAmount'),
+ u64('punishCoinAmount'),
+ u64('orderbookToInitTime'),
+ u128('swapBaseInAmount'),
+ u128('swapQuoteOutAmount'),
+ u64('swapBase2QuoteFee'),
+ u128('swapQuoteInAmount'),
+ u128('swapBaseOutAmount'),
+ u64('swapQuote2BaseFee'),
+ // amm vault
+ publicKey('baseVault'),
+ publicKey('quoteVault'),
+ // mint
+ publicKey('baseMint'),
+ publicKey('quoteMint'),
+ publicKey('lpMint'),
+ // market
+ publicKey('openOrders'),
+ publicKey('marketId'),
+ publicKey('marketProgramId'),
+ publicKey('targetOrders'),
+ publicKey('withdrawQueue'),
+ publicKey('lpVault'),
+ publicKey('owner'),
+ // true circulating supply without lock up
+ u64('lpReserve'),
+ seq(u64(), 3, 'padding'),
+])
+
+// CP_AMM CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
+const CPAMM_LAYOUT = struct([
+ blob(8),
+ publicKey("configId"),
+ publicKey("poolCreator"),
+ publicKey("vaultA"),
+ publicKey("vaultB"),
+ publicKey("mintLp"),
+ publicKey("mintA"),
+ publicKey("mintB"),
+ publicKey("mintProgramA"),
+ publicKey("mintProgramB"),
+ publicKey("observationId"),
+ u8("bump"),
+ u8("status"),
+ u8("lpDecimals"),
+ u8("mintDecimalA"),
+ u8("mintDecimalB"),
+ u64("lpAmount"),
+ u64("protocolFeesMintA"),
+ u64("protocolFeesMintB"),
+ u64("fundFeesMintA"),
+ u64("fundFeesMintB"),
+ u64("openTime"),
+ seq(u64(), 32),
+])
+
+// CLMM
+
+const RewardInfo = struct([
+ u8("rewardState"),
+ u64("openTime"),
+ u64("endTime"),
+ u64("lastUpdateTime"),
+ u128("emissionsPerSecondX64"),
+ u64("rewardTotalEmissioned"),
+ u64("rewardClaimed"),
+ publicKey("tokenMint"),
+ publicKey("tokenVault"),
+ publicKey("creator"),
+ u128("rewardGrowthGlobalX64"),
+]);
+
+const CLMM_LAYOUT = struct([
+ blob(8),
+ u8("bump"),
+ publicKey("ammConfig"),
+ publicKey("creator"),
+ publicKey("mintA"),
+ publicKey("mintB"),
+ publicKey("vaultA"),
+ publicKey("vaultB"),
+ publicKey("observationId"),
+ u8("mintDecimalsA"),
+ u8("mintDecimalsB"),
+ u16("tickSpacing"),
+ u128("liquidity"),
+ u128("sqrtPriceX64"),
+ i32("tickCurrent"),
+ u32(),
+ u128("feeGrowthGlobalX64A"),
+ u128("feeGrowthGlobalX64B"),
+ u64("protocolFeesTokenA"),
+ u64("protocolFeesTokenB"),
+ u128("swapInAmountTokenA"),
+ u128("swapOutAmountTokenB"),
+ u128("swapInAmountTokenB"),
+ u128("swapOutAmountTokenA"),
+ u8("status"),
+ seq(u8(), 7, ""),
+ seq(RewardInfo, 3, "rewardInfos"),
+ seq(u64(), 16, "tickArrayBitmap"),
+ u64("totalFeesTokenA"),
+ u64("totalFeesClaimedTokenA"),
+ u64("totalFeesTokenB"),
+ u64("totalFeesClaimedTokenB"),
+ u64("fundFeesTokenA"),
+ u64("fundFeesTokenB"),
+ u64("startTime"),
+ seq(u64(), 15 * 4 - 3, "padding"),
+]);
+
+export {
+ AMM_LAYOUT,
+ CPAMM_LAYOUT,
+ CLMM_LAYOUT,
+ MARKET_LAYOUT,
+}
diff --git a/src/platforms/solana/raydium/pairs.js b/src/platforms/solana/raydium/pairs.js
new file mode 100644
index 0000000..553b358
--- /dev/null
+++ b/src/platforms/solana/raydium/pairs.js
@@ -0,0 +1,64 @@
+/*#if _EVM
+
+/*#elif _SOLANA
+
+//#else */
+
+//#endif
+
+import { ethers } from 'ethers'
+import { getPairsWithPrice as getPairsWithPriceAMM } from './amm/pairs'
+import { getPairsWithPrice as getPairsWithPriceCPAMM } from './cpamm/pairs'
+import { getPairsWithPrice as getPairsWithPriceCLMM } from './clmm/pairs'
+
+const getParisWithPriceForAllTypes = ({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ return Promise.all([
+ getPairsWithPriceAMM({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPriceCPAMM({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ getPairsWithPriceCLMM({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }),
+ ]).then((pairsAMM, pairsCPAMM, pairsCLMNN)=>{
+ return [
+ (pairsAMM || []).filter(Boolean).flat(),
+ (pairsCPAMM || []).filter(Boolean).flat(),
+ (pairsCLMNN || []).filter(Boolean).flat()
+ ].flat()
+ })
+}
+
+const getPairsWithPrice = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })=>{
+ try {
+ return await getParisWithPriceForAllTypes({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })
+ } catch {
+ return []
+ }
+}
+
+let getHighestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).gt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+}
+
+let getLowestPrice = (pairs)=>{
+ return pairs.reduce((bestPricePair, currentPair)=> ethers.BigNumber.from(currentPair.price).lt(ethers.BigNumber.from(bestPricePair.price)) ? currentPair : bestPricePair)
+}
+
+let getBestPair = async({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ const pairs = await getPairsWithPrice({ tokenIn, tokenOut, amountIn, amountInMax, amountOut, amountOutMin })
+
+ if(!pairs || pairs.length === 0) { return }
+
+ let bestPair
+
+ if(amountIn || amountInMax) {
+ bestPair = getHighestPrice(pairs)
+ } else { // amount out
+ bestPair = getLowestPrice(pairs)
+ }
+
+ return bestPair
+}
+
+export {
+ getPairsWithPrice,
+ getBestPair,
+}
+
diff --git a/src/platforms/solana/raydium/path.js b/src/platforms/solana/raydium/path.js
new file mode 100644
index 0000000..c7eeed4
--- /dev/null
+++ b/src/platforms/solana/raydium/path.js
@@ -0,0 +1,91 @@
+import Blockchains from '@depay/web3-blockchains'
+import { getPairsWithPrice } from './pairs'
+
+const blockchain = Blockchains.solana
+
+// Replaces 11111111111111111111111111111111 with the wrapped token and implies wrapping.
+//
+// We keep 11111111111111111111111111111111 internally
+// to be able to differentiate between SOL<>Token and WSOL<>Token swaps
+// as they are not the same!
+//
+let getExchangePath = ({ path }) => {
+ if(!path) { return }
+ let exchangePath = path.map((token, index) => {
+ if (
+ token === blockchain.currency.address && path[index+1] != blockchain.wrapped.address &&
+ path[index-1] != blockchain.wrapped.address
+ ) {
+ return blockchain.wrapped.address
+ } else {
+ return token
+ }
+ })
+
+ if(exchangePath[0] == blockchain.currency.address && exchangePath[1] == blockchain.wrapped.address) {
+ exchangePath.splice(0, 1)
+ } else if(exchangePath[exchangePath.length-1] == blockchain.currency.address && exchangePath[exchangePath.length-2] == blockchain.wrapped.address) {
+ exchangePath.splice(exchangePath.length-1, 1)
+ }
+
+ return exchangePath
+}
+
+let pathExists = async ({ path, amountIn, amountInMax, amountOut, amountOutMin }) => {
+ if(path.length == 1) { return false }
+ path = getExchangePath({ path })
+ let pairs = []
+ if((await getPairsWithPrice({ tokenIn: path[0], tokenOut: path[1], amountIn, amountInMax, amountOut, amountOutMin })).length > 0) {
+ return true
+ } else {
+ return false
+ }
+}
+
+let findPath = async ({ tokenIn, tokenOut, amountIn, amountOut, amountInMax, amountOutMin }) => {
+ if(
+ [tokenIn, tokenOut].includes(blockchain.currency.address) &&
+ [tokenIn, tokenOut].includes(blockchain.wrapped.address)
+ ) { return { path: undefined, exchangePath: undefined } }
+
+ let path, stablesIn, stablesOut, stable
+
+ if (await pathExists({ path: [tokenIn, tokenOut], amountIn, amountInMax, amountOut, amountOutMin })) {
+ // direct path
+ path = [tokenIn, tokenOut]
+ } else if (
+ tokenIn != blockchain.wrapped.address &&
+ tokenIn != blockchain.currency.address &&
+ await pathExists({ path: [tokenIn, blockchain.wrapped.address], amountIn, amountInMax, amountOut, amountOutMin }) &&
+ tokenOut != blockchain.wrapped.address &&
+ tokenOut != blockchain.currency.address &&
+ await pathExists({ path: [tokenOut, blockchain.wrapped.address], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) })
+ ) {
+ // path via blockchain.wrapped.address
+ path = [tokenIn, blockchain.wrapped.address, tokenOut]
+ } else if (
+ !blockchain.stables.usd.includes(tokenIn) &&
+ (stablesIn = (await Promise.all(blockchain.stables.usd.map(async(stable)=>await pathExists({ path: [tokenIn, stable], amountIn, amountInMax, amountOut, amountOutMin }) ? stable : undefined))).filter(Boolean)) &&
+ !blockchain.stables.usd.includes(tokenOut) &&
+ (stablesOut = (await Promise.all(blockchain.stables.usd.map(async(stable)=>await pathExists({ path: [tokenOut, stable], amountIn: (amountOut||amountOutMin), amountInMax: (amountOut||amountOutMin), amountOut: (amountIn||amountInMax), amountOutMin: (amountIn||amountInMax) }) ? stable : undefined))).filter(Boolean)) &&
+ (stable = stablesIn.filter((stable)=> stablesOut.includes(stable))[0])
+ ) {
+ // path via TOKEN_IN <> STABLE <> TOKEN_OUT
+ path = [tokenIn, stable, tokenOut]
+ }
+
+ // Add blockchain.wrapped.address to route path if things start or end with blockchain.currency.address
+ // because that actually reflects how things are routed in reality:
+ if(path?.length && path[0] == blockchain.currency.address) {
+ path.splice(1, 0, blockchain.wrapped.address)
+ } else if(path?.length && path[path.length-1] == blockchain.currency.address) {
+ path.splice(path.length-1, 0, blockchain.wrapped.address)
+ }
+ return { path, exchangePath: getExchangePath({ path }) }
+}
+
+export {
+ findPath,
+ getExchangePath,
+ pathExists,
+}
diff --git a/src/platforms/solana/raydium/transaction.js b/src/platforms/solana/raydium/transaction.js
new file mode 100644
index 0000000..53faa59
--- /dev/null
+++ b/src/platforms/solana/raydium/transaction.js
@@ -0,0 +1,307 @@
+/*#if _EVM
+
+/*#elif _SOLANA
+
+import { request, getProvider } from '@depay/web3-client-solana'
+import Token from '@depay/web3-tokens-solana'
+
+//#else */
+
+import { request, getProvider } from '@depay/web3-client'
+import Token from '@depay/web3-tokens'
+
+//#endif
+
+import Blockchains from '@depay/web3-blockchains'
+import { Buffer, BN, Transaction, TransactionInstruction, SystemProgram, PublicKey, Keypair, struct, u8, u64, u128, bool } from '@depay/solana-web3.js'
+import { getExchangePath } from './path'
+import { getBestPair } from './pairs'
+import { MARKET_LAYOUT } from './layouts'
+
+const blockchain = Blockchains.solana
+
+const getAssociatedAuthority = async(programId)=> {
+ let [publicKey, nonce] = await PublicKey.findProgramAddress(
+ // new Uint8Array(Buffer.from('amm authority'.replace('\u00A0', ' '), 'utf-8'))
+ [Buffer.from([97, 109, 109, 32, 97, 117, 116, 104, 111, 114, 105, 116, 121])],
+ programId,
+ )
+ return publicKey
+}
+
+const getAssociatedMarketAuthority = async(programId, marketId)=> {
+ let [publicKey, nonce] = await PublicKey.findProgramAddress(
+ // Seed is the marketId
+ [marketId.toBuffer()],
+ // Program ID for OpenBook/Serum
+ programId
+ )
+ return publicKey
+}
+
+const getTransaction = async({
+ path,
+ amountIn,
+ amountInMax,
+ amountOut,
+ amountOutMin,
+ amounts,
+ amountInInput,
+ amountOutInput,
+ amountInMaxInput,
+ amountOutMinInput,
+ account
+})=>{
+ let transaction = { blockchain: 'solana' }
+ let instructions = []
+
+ const exchangePath = getExchangePath({ path })
+ if(exchangePath.length > 3) { throw 'Raydium can only handle fixed paths with a max length of 3 (2 pools)!' }
+ const tokenIn = exchangePath[0]
+ const tokenMiddle = exchangePath.length == 3 ? exchangePath[1] : undefined
+ const tokenOut = exchangePath[exchangePath.length-1]
+
+ let pairs, amountMiddle
+ if(exchangePath.length == 2) {
+ pairs = [await getBestPair({ tokenIn, tokenOut, amountIn: (amountInInput || amountInMaxInput), amountOut: (amountOutInput || amountOutMinInput) })]
+ } else {
+ if(amountInInput || amountInMaxInput) {
+ pairs = [await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountIn: (amountInInput || amountInMaxInput) })]
+ pairs.push(await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountIn: pairs[0].price }))
+ } else { // originally amountOut
+ pairs = [await getBestPair({ tokenIn: tokenMiddle, tokenOut, amountOut: (amountOutInput || amountOutMinInput) })]
+ pairs.unshift(await getBestPair({ tokenIn, tokenOut: tokenMiddle, amountOut: pairs[0].price }))
+ }
+ }
+
+ let startsWrapped = (path[0] === blockchain.currency.address && exchangePath[0] === blockchain.wrapped.address)
+ let endsUnwrapped = (path[path.length-1] === blockchain.currency.address && exchangePath[exchangePath.length-1] === blockchain.wrapped.address)
+ let wrappedAccount
+ const provider = await getProvider('solana')
+
+ if(startsWrapped || endsUnwrapped) {
+ const rent = await provider.getMinimumBalanceForRentExemption(Token.solana.TOKEN_LAYOUT.span)
+ const keypair = Keypair.generate()
+ wrappedAccount = keypair.publicKey.toString()
+ const lamports = startsWrapped ? new BN(amountIn.toString()).add(new BN(rent)) : new BN(rent)
+ let createAccountInstruction = SystemProgram.createAccount({
+ fromPubkey: new PublicKey(account),
+ newAccountPubkey: new PublicKey(wrappedAccount),
+ programId: new PublicKey(Token.solana.TOKEN_PROGRAM),
+ space: Token.solana.TOKEN_LAYOUT.span,
+ lamports
+ })
+ createAccountInstruction.signers = [keypair]
+ instructions.push(createAccountInstruction)
+ instructions.push(
+ Token.solana.initializeAccountInstruction({
+ account: wrappedAccount,
+ token: blockchain.wrapped.address,
+ owner: account
+ })
+ )
+ }
+
+ if(pairs.length === 1) { // single hop
+ const tokenAccountIn = startsWrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenIn }))
+ const tokenAccountOut = endsUnwrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenOut }))
+ const pool = pairs[0]
+ const market = await request(`solana://${pool.data.marketId}/getAccountInfo`, { api: MARKET_LAYOUT })
+
+ let LAYOUT, data
+ LAYOUT = struct([
+ u8('instruction'),
+ u64('amountIn'),
+ u64('minAmountOut')
+ ])
+ data = Buffer.alloc(LAYOUT.span)
+ LAYOUT.encode(
+ {
+ instruction: 9,
+ amountIn: new BN((amountIn || amountInMax).toString()),
+ minAmountOut: new BN((amountOutMin || amountOut).toString()),
+ },
+ data,
+ )
+
+ // if(!endsUnwrapped) {
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenOut, account: tokenAccountOut })
+ // }
+
+ // let keys = [
+ // // token_program
+ // { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // // amm
+ // { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // // amm authority
+ // { pubkey: await getAssociatedAuthority(new PublicKey(pool.publicKey)), isWritable: false, isSigner: false },
+ // // amm openOrders
+ // { pubkey: new PublicKey(pool.data.openOrders), isWritable: true, isSigner: false },
+ // // amm baseVault
+ // { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // // amm quoteVault
+ // { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // // openbook marketProgramId
+ // { pubkey: new PublicKey(pool.data.marketProgramId), isWritable: false, isSigner: false },
+ // // openbook marketId
+ // { pubkey: new PublicKey(pool.data.marketId), isWritable: true, isSigner: false },
+ // // openbook marketBids
+ // { pubkey: market.bids, isWritable: true, isSigner: false },
+ // // openbook marketAsks
+ // { pubkey: market.asks, isWritable: true, isSigner: false },
+ // // openbook eventQueue
+ // { pubkey: market.eventQueue, isWritable: true, isSigner: false },
+ // // openbook baseVault
+ // { pubkey: market.baseVault, isWritable: true, isSigner: false },
+ // // openbook quoteVault
+ // { pubkey: market.quoteVault, isWritable: true, isSigner: false },
+ // // openbook marketAuthority
+ // { pubkey: await getAssociatedMarketAuthority(pool.data.marketProgramId, pool.data.marketId), isWritable: false, isSigner: false },
+ // // user tokenAccountIn
+ // { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // // user tokenAccountOut
+ // { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // // user owner
+ // { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ // ]
+
+ let keys = [
+ // token_program
+ { pubkey: new PublicKey(Token.solana.TOKEN_PROGRAM), isWritable: false, isSigner: false },
+ // amm
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm authority
+ { pubkey: new PublicKey('5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1'), isWritable: false, isSigner: false },
+ // amm openOrders
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // amm baseVault
+ { pubkey: new PublicKey(pool.data.baseVault), isWritable: true, isSigner: false },
+ // amm quoteVault
+ { pubkey: new PublicKey(pool.data.quoteVault), isWritable: true, isSigner: false },
+ // openbook marketProgramId
+ { pubkey: new PublicKey(pool.publicKey), isWritable: false, isSigner: false },
+ // openbook marketId
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketBids
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAsks
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook eventQueue
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook baseVault
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook quoteVault
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // openbook marketAuthority
+ { pubkey: new PublicKey(pool.publicKey), isWritable: true, isSigner: false },
+ // user tokenAccountIn
+ { pubkey: tokenAccountIn, isWritable: true, isSigner: false },
+ // user tokenAccountOut
+ { pubkey: tokenAccountOut, isWritable: true, isSigner: false },
+ // user owner
+ { pubkey: new PublicKey(account), isWritable: true, isSigner: true }
+ ]
+
+ console.log('keys', JSON.stringify(keys))
+
+ instructions.push(
+ new TransactionInstruction({
+ programId: new PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'),
+ keys,
+ data,
+ })
+ )
+ } else if (pairs.length === 2) { // two hop
+ // // amount is NOT the precise part of the swap (otherAmountThreshold is)
+ // let amountSpecifiedIsInput = !!(amountInInput || amountOutMinInput)
+ // let amount = amountSpecifiedIsInput ? amountIn : amountOut
+ // let otherAmountThreshold = amountSpecifiedIsInput ? amountOutMin : amountInMax
+ // let tokenAccountIn = startsWrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenIn }))
+ // let tokenMiddle = exchangePath[1]
+ // let tokenAccountMiddle = new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenMiddle }))
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenMiddle, account: tokenAccountMiddle })
+ // let tokenAccountOut = endsUnwrapped ? new PublicKey(wrappedAccount) : new PublicKey(await Token.solana.findProgramAddress({ owner: account, token: tokenOut }))
+ // if(!endsUnwrapped) {
+ // await createTokenAccountIfNotExisting({ instructions, owner: account, token: tokenOut, account: tokenAccountOut })
+ // }
+ // instructions.push(
+ // new TransactionInstruction({
+ // programId: new PublicKey('whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc'),
+ // keys: await getTwoHopSwapInstructionKeys({
+ // account,
+ // poolOne: pairs[0].pubkey,
+ // tickArraysOne: pairs[0].tickArrays,
+ // tokenAccountOneA: pairs[0].aToB ? tokenAccountIn : tokenAccountMiddle,
+ // tokenVaultOneA: pairs[0].data.tokenVaultA,
+ // tokenAccountOneB: pairs[0].aToB ? tokenAccountMiddle : tokenAccountIn,
+ // tokenVaultOneB: pairs[0].data.tokenVaultB,
+ // poolTwo: pairs[1].pubkey,
+ // tickArraysTwo: pairs[1].tickArrays,
+ // tokenAccountTwoA: pairs[1].aToB ? tokenAccountMiddle : tokenAccountOut,
+ // tokenVaultTwoA: pairs[1].data.tokenVaultA,
+ // tokenAccountTwoB: pairs[1].aToB ? tokenAccountOut : tokenAccountMiddle,
+ // tokenVaultTwoB: pairs[1].data.tokenVaultB,
+ // }),
+ // data: getTwoHopSwapInstructionData({
+ // amount,
+ // otherAmountThreshold,
+ // amountSpecifiedIsInput,
+ // aToBOne: pairs[0].aToB,
+ // aToBTwo: pairs[1].aToB,
+ // sqrtPriceLimitOne: pairs[0].sqrtPriceLimit,
+ // sqrtPriceLimitTwo: pairs[1].sqrtPriceLimit,
+ // }),
+ // })
+ // )
+ }
+
+ if(startsWrapped || endsUnwrapped) {
+ instructions.push(
+ Token.solana.closeAccountInstruction({
+ account: wrappedAccount,
+ owner: account
+ })
+ )
+ }
+
+ // await debug(instructions, provider)
+
+ transaction.instructions = instructions
+ return transaction
+}
+
+const debug = async(instructions, provider)=>{
+ console.log('instructions.length', instructions.length)
+ let data
+ instructions.forEach((instruction)=>{
+ console.log('INSTRUCTION.programId', instruction.programId.toString())
+ console.log('INSTRUCTION.keys', instruction.keys)
+ try {
+ const LAYOUT = struct([
+ u64("anchorDiscriminator"),
+ u64("amount"),
+ u64("otherAmountThreshold"),
+ u128("sqrtPriceLimit"),
+ bool("amountSpecifiedIsInput"),
+ bool("aToB"),
+ ])
+ data = LAYOUT.decode(instruction.data)
+ } catch {}
+ })
+ if(data) {
+ console.log('INSTRUCTION.data', data)
+ console.log('amount', data.amount.toString())
+ console.log('otherAmountThreshold', data.otherAmountThreshold.toString())
+ console.log('sqrtPriceLimit', data.sqrtPriceLimit.toString())
+ }
+ let simulation = new Transaction({ feePayer: new PublicKey('2UgCJaHU5y8NC4uWQcZYeV9a5RyYLF7iKYCybCsdFFD1') })
+ instructions.forEach((instruction)=>simulation.add(instruction))
+ let result
+ console.log('SIMULATE')
+ try{ result = await provider.simulateTransaction(simulation) } catch(e) { console.log('error', e) }
+ console.log('SIMULATION RESULT', result)
+}
+
+export {
+ getTransaction,
+}