Skip to content

Commit

Permalink
wallet swap
Browse files Browse the repository at this point in the history
  • Loading branch information
abrzezinski94 committed Jul 3, 2024
1 parent 2dda459 commit 4e6dc4c
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 9 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@
"@blockworks-foundation/mango-feeds": "0.1.7",
"@blockworks-foundation/mango-v4": "0.31.3",
"@blockworks-foundation/mango-v4-settings": "0.14.24",
"@blockworks-foundation/mangolana": "0.0.17",
"@glitchful-dev/sol-apy-sdk": "3.0.2",
"@headlessui/react": "1.6.6",
"@heroicons/react": "2.0.10",
"@project-serum/anchor": "0.25.0",
"@project-serum/anchor": "0.26.0",
"@pythnetwork/client": "2.15.0",
"@raydium-io/raydium-sdk": "1.3.1-beta.57",
"@solana/spl-governance": "0.3.27",
Expand Down
163 changes: 162 additions & 1 deletion utils/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
Bank,
FlashLoanType,
Group,
MANGO_ROUTER_API_URL,
MangoAccount,
MangoClient,
MangoError,
MangoSignatureStatus,
RouteInfo,
TokenIndex,
Expand All @@ -15,6 +17,7 @@ import {
toNative,
toNativeI80F48,
toUiDecimals,
tryStringify,
} from '@blockworks-foundation/mango-v4'
import { TOKEN_PROGRAM_ID } from '@solana/spl-governance'
import {
Expand All @@ -28,16 +31,22 @@ import {
Connection,
Keypair,
PublicKey,
RpcResponseAndContext,
SYSVAR_INSTRUCTIONS_PUBKEY,
SignatureResult,
SystemProgram,
Transaction,
TransactionInstruction,
TransactionMessage,
VersionedTransaction,
} from '@solana/web3.js'
import { floorToDecimal } from './numbers'
import { BOOST_ACCOUNT_PREFIX } from './constants'
import { BOOST_ACCOUNT_PREFIX, JUPITER_V6_QUOTE_API_MAINNET } from './constants'
import { notify } from './notifications'
import { getStakableTokensDataForMint } from './tokens'
import { JupiterV6RouteInfo } from 'types/jupiter'
import { WalletContextState } from '@solana/wallet-adapter-react'
import { awaitTransactionSignatureConfirmation } from '@blockworks-foundation/mangolana/lib/transactions'

export const withdrawAndClose = async (
client: MangoClient,
Expand Down Expand Up @@ -962,3 +971,155 @@ export const getNextAccountNumber = (accounts: MangoAccount[]): number => {
}
return 0
}

export const walletSwap = async (
selectedRoute: JupiterV6RouteInfo,
connection: Connection,
slippage: number,
wallet: WalletContextState,
client: MangoClient,
) => {
const vtx = await fetchJupiterWalletSwapTransaction(
selectedRoute,
wallet!.publicKey!,
slippage,
selectedRoute.origin,
)

const latestBlockhash = await connection.getLatestBlockhash()
const sign = wallet.signTransaction!
const signed = await sign(vtx)

const txid = await sendTxAndConfirm(
client.opts.multipleConnections,
connection,
signed,
latestBlockhash,
)
return { txid }
}

/** Given a Jupiter route, fetch the transaction for the user to sign.
**This function should ONLY be used for wallet swaps* */
export const fetchJupiterWalletSwapTransaction = async (
selectedRoute: JupiterV6RouteInfo,
userPublicKey: PublicKey,
slippage: number,
origin?: 'mango' | 'jupiter' | 'raydium',
): Promise<VersionedTransaction> => {
// docs https://station.jup.ag/api-v6/post-swap
const params: {
quoteResponse: JupiterV6RouteInfo
userPublicKey: PublicKey
slippageBps: number
autoCreateOutAta?: boolean
wrapAndUnwrapSol?: boolean
} = {
// response from /quote api
quoteResponse: selectedRoute,
// user public key to be used for the swap
userPublicKey,
slippageBps: Math.ceil(slippage * 100),
}

if (origin === 'mango') {
params.autoCreateOutAta = true
params.wrapAndUnwrapSol = true
}

const transactions = await (
await fetch(
`${
origin === 'mango' ? MANGO_ROUTER_API_URL : JUPITER_V6_QUOTE_API_MAINNET
}/swap`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
},
)
).json()

const { swapTransaction } = transactions
const parsedSwapTransaction = VersionedTransaction.deserialize(
Buffer.from(swapTransaction, 'base64'),
)
return parsedSwapTransaction
}

export const sendTxAndConfirm = async (
multipleConnections: Connection[] = [],
connection: Connection,
tx: Transaction | VersionedTransaction,
latestBlockhash: {
lastValidBlockHeight: number
blockhash: string
},
) => {
let signature = ''
const abortController = new AbortController()
try {
const allConnections = [connection, ...multipleConnections]
const rawTransaction = tx.serialize()
signature = await Promise.any(
allConnections.map((c) => {
return c.sendRawTransaction(rawTransaction, {
skipPreflight: true,
})
}),
)
await Promise.any(
allConnections.map((c) =>
awaitTransactionSignatureConfirmation({
txid: signature,
confirmLevel: 'processed',
connection: c,
timeoutStrategy: {
block: latestBlockhash,
},
abortSignal: abortController.signal,
}),
),
)
abortController.abort()
return signature
} catch (e) {
abortController.abort()
if (e instanceof AggregateError) {
for (const individualError of e.errors) {
const stringifiedError = tryStringify(individualError)
throw new MangoError({
txid: signature,
message: `${
stringifiedError
? stringifiedError
: individualError
? individualError
: 'Unknown error'
}`,
})
}
}
if (isErrorWithSignatureResult(e)) {
const stringifiedError = tryStringify(e?.value?.err)
throw new MangoError({
txid: signature,
message: `${stringifiedError ? stringifiedError : e?.value?.err}`,
})
}
const stringifiedError = tryStringify(e)
throw new MangoError({
txid: signature,
message: `${stringifiedError ? stringifiedError : e}`,
})
}
}

function isErrorWithSignatureResult(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
err: any,
): err is RpcResponseAndContext<SignatureResult> {
return err && typeof err.value !== 'undefined'
}
22 changes: 15 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@
superstruct "^0.15.4"
toml "^3.0.0"

"@coral-xyz/borsh@^0.26.0":
version "0.26.0"
resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.26.0.tgz#d054f64536d824634969e74138f9f7c52bbbc0d5"
integrity sha512-uCZ0xus0CszQPHYfWAqKS5swS1UxvePu83oOF+TWpUkedsNlg6p2p4azxZNSSqwXb9uXMFgxhuMBX9r3Xoi0vQ==
dependencies:
bn.js "^5.1.2"
buffer-layout "^1.2.0"

"@coral-xyz/borsh@^0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.27.0.tgz#700c647ea5262b1488957ac7fb4e8acf72c72b63"
Expand Down Expand Up @@ -1375,18 +1383,18 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==

"@project-serum/anchor@0.25.0":
version "0.25.0"
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.25.0.tgz#88ee4843336005cf5a64c80636ce626f0996f503"
integrity sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A==
"@project-serum/anchor@0.26.0":
version "0.26.0"
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.26.0.tgz#99e15a3923a5d10514f8185b2d3909e5699d60d5"
integrity sha512-Nq+COIjE1135T7qfnOHEn7E0q39bQTgXLFk837/rgFe6Hkew9WML7eHsS+lSYD2p3OJaTiUOHTAq1lHy36oIqQ==
dependencies:
"@project-serum/borsh" "^0.2.5"
"@solana/web3.js" "^1.36.0"
"@coral-xyz/borsh" "^0.26.0"
"@solana/web3.js" "^1.68.0"
base64-js "^1.5.1"
bn.js "^5.1.2"
bs58 "^4.0.1"
buffer-layout "^1.2.2"
camelcase "^5.3.1"
camelcase "^6.3.0"
cross-fetch "^3.1.5"
crypto-hash "^1.3.0"
eventemitter3 "^4.0.7"
Expand Down

0 comments on commit 4e6dc4c

Please sign in to comment.