🤝🏻 合作-API:🕹集成GMGN Solana交易API

欢迎集成GMGN的Solana交易API进行快速量化交易。

1.查询路由接入点(支持防夹):

https://gmgn.ai/defi/router/v1/sol/tx/get_swap_route?token_in_address=${inputToken}&token_out_address=${outputToken}&in_amount=${amount}&from_address=${fromAddress}&slippage=${slippage}

请求方式: GET

API Key: 免费使用,不需要申请API Key

输入参数:

参数名
类型
说明

token_in_address

string

兑换要花的币,输入代币地址,例如: So11111111111111111111111111111111111111112

token_out_address

string

兑换目标币地址,例如:7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs

in_amount

string

最小单位lamports,100000000=0.1SOL

from_address

string

发起交易钱包地址,例如:2kpJ5QRh16aRQ4oLZ5LnucHFDAZtEFz6omqWWMzDSNrx

slippage

float

滑点,%之上的数值,比如10表示10%

swap_mode

string

ExactIn或者ExactOut,默认不传则是ExactIn

fee

float

网络和节点优先费。例如0.006, 单位SOL。GMGN会自动分配节点贿赂小费和网络优先费。 如果开防夹,fee需要至少 0.002

is_anti_mev

bool

可选,防夹交易时设为true

partner

string

可选,合作伙伴来源名称

返回参数:

参数名
类型
说明

code

int

错误码,0

msg

string

结果描述,success

data

Object

{

quote: {

inputMint: 'So11111111111111111111111111111111111111112',

inAmount: '50000000',

outputMint: '7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs',

outAmount: '77920478752',

otherAmountThreshold: '77530876359',

swapMode: 'ExactIn',

slippageBps: 50,

platformFee: null,

priceImpactPct: '0',

routePlan: [Array],

contextSlot: 240893434,

timeTaken: 0.04250061

},

raw_tx: {

swapTransaction: 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAIDxoVIz70VFGJdL5OoCKmFca4NP2MXOcNEiFO6y6JoFUNGWxA6mmc96B1sKHdcYHTM1M1QYNOOSahRPMddzM8XdRsp8RcOMdvjkujt1otIW/R6tIhAHlyC8kUDXj133RK+Ye1I/p3Gy551653GdDPX3KX0D4dWPXyZvsBemb3XlwHyQ+0ezK8pEPmQbXwZ8Tz3O52/YACoT20v0iE4A7D1bTgIWD7ScmJ4Koq6/mSOQVxqfFkoUZ5qTF4TbXDFfH1U+qMakgEp96ZVF6SJaXlGdV6w0mXkHJVedqOxh5rfjqMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAAR51VvyMcBu7nTFbs5oFQf9sbLeo/SOUQKxzaJWvBOPBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKlcnp1fowmGSs19gRjTJjE83nuG3xjhl5JKAxhv/p89eoKX5UT/REBqE7f6ZMLP+j7G4V34k14Ax0Fw3q7wE/N9jJclj04kifG7PRApFI4NgwtaE5na/xCEBI572Nvp+Fm0P/on9df2SnTAmx8pWHneSwmrNt/J3VFLMhqns4zl6PSRqslFk9OGKukg94vbePj7SOGor/mX5COZhlMmlOYbCAgABQI6UwcACAAJAyBOAAAAAAAADQYABQAnBwoBAQcCAAUMAgAAAIDw+gIAAAAACgEFARENBgACAAsHCgEBCTMKDAAFAwYCJwsJCQ4JIAoMHAMdAR4aHxsoIiMYDAEEFxkWFQokJiUgCgwSBhMEFBAPESEuwSCbM0HWnIEGAwAAABEBZAABGWQBAhEAZAIDgPD6AgAAAAAgJmwkEgAAADIAAAoDBQAAAQkDegmW2ZAMszm+4Eneq5orFPHiSoriEDigyGyG9FUTd+oGpqilp6GiAp+jq4YFkrWa2UlUnmJKVsvmeovDYVI3GhRB1TB5/repN9MFSEVDREcFQkxGSUuC/JDNwibla4b9UHQsSYKI/HmR9edfsxbKg36RCgUpKAaNi5CGiogCkY4=',

lastValidBlockHeight: 221852977,

prioritizationFeeLamports: 9601,

recentBlockhash: 'HThJomQ74BKBYYfFewg9m5MrRwAsHjrpuTwEcohxpAEW'

}

}

返回data.quote字段说明:

参数名
类型
说明

inputMint

string

输入币种的地址,So11111111111111111111111111111111111111112

inAmount

string

输入币种数量,最小单位lamports

outputMint

string

输出币种地址,7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs

outputAmount

string

路由计算输出理论值,最小单位lamports

otherAmountThreshold

string

计算进滑点的值,最小单位lamports

swapMode

string

ExactIn或者ExactOut

slippageBps

50

滑点Bps值,10000为分母上面的值

platformFee

string

平台费,null

priceImpact

string

价格影响比例,0

routePlan

Array

路由步骤

contextSlot

int

slot数

timeTaken

float

寻路花费时间,秒

上面的routePlan 类型说明:

返回data.raw_tx字段说明:

参数名

类型

说明

swapTransaction

string

base64编码的待签名tx

lastValidBlockHeight

int

打包待签名tx时的区块高度,221852977

recentBlockhash

string

打包待签名tx时的最新上链的块hash,HThJomQ74BKBYYfFewg9m5MrRwAsHjrpuTwEcohxpAEW

prioritizationFeeLamports

int

推荐优先费用,最小单位lamports,9601

2. 提交交易接入点(非防夹):

https://gmgn.ai/defi/router/v1/sol/tx/submit_signed_transaction

请求方式:POST

拿到路由接口返回后,需要用base64解码并且使用VersionedTransaction反序列化,并用本地钱包签名,签名之后用base64 encode之后post给接口:

  const swapTransactionBuf = Buffer.from(route.data.raw_tx.swapTransaction, 'base64')
  const transaction = VersionedTransaction.deserialize(swapTransactionBuf)
  transaction.sign([wallet.payer])
  const signedTx = transaction.serialize().toString('base64')

请求参数:

参数名

类型

说明

signed_tx

string

签名后的交易,使用base64 encode之后的字串

返回字段:

参数名

类型

说明

code

int

错误码,0

msg

string

错误信息,success

data

Object

{

hash: '3Qr9Kb8XfQiTa2E4butFRdVgWb9jTorcQaCPx3zx9fETyZhnffVdjagGU7PkwJVX8X9Js4xvUjybCaNjvFGozoLR'

}

3. 提交交易接入点(防夹交易Anti-MEV)

https://gmgn.ai/defi/router/v1/sol/tx/submit_signed_bundle_transaction

请求方式:POST

拿到路由接口返回后,需要用base64解码并且使用VersionedTransaction反序列化,并用本地钱包签名,签名之后用bs64 encode之后post给接口:

const swapTransactionBuf = Buffer.from(route.data.raw_tx.swapTransaction, 'base64') const transaction = VersionedTransaction.deserialize(swapTransactionBuf) transaction.sign([wallet.payer]) const signedTx = Buffer.from(transaction.serialize()).toString("base64")

请求参数:

参数名

类型

说明

signed_tx

string

签名后的交易,使用base64 encode之后的字串

from_address

string

用户钱包地址

返回字段:

参数名

类型

说明

参数名

类型

说明

code

int

错误码,0

msg

string

错误信息,success

data

Object

{

order_id: '69D41199-5D62-4225-98C0-1FC3BA428958',

bundle_id: '3Qr9Kb8XfQiTa2E4butFRdVgWb9jTorcQaCPx3zx9fETyZhnffVdjagGU7PkwJVX8X9Js4xvUjybCaNjvFGozoLR',

last_valid_block_number: 123456744,

tx_hash: '2atVpaMiGLwEsJsJZtT9B9DnMALofTWHmWHMAdo3kSks9Ap3NdChz73umNoUsogbyFgR5zUsAN9X8bdfPnpGHHfV'

},

4. 查询交易状态接入点:

https://gmgn.ai/defi/router/v1/sol/tx/get_transaction_status?hash=${hash}&last_valid_height

请求方式:GET

请求参数:

参数名
类型
说明

hash

string

提交完交易后返回的hash,例如3Qr9Kb8XfQiTa2E4butFRdVgWb9jTorcQaCPx3zx9fETyZhnffVdjagGU7PkwJVX8X9Js4xvUjybCaNjvFGozoLR

last_valid_height

int

路由接口返回的待签名交易打包时的块高度,例如221852977

返回字段:

参数名
类型
说明

code

int

0

msg

string

success

data

Object

{ success: true, expired: false }

data字段说明:

success: 是否成功上链, true则为成功上链。

failed: 是否上链且失败, true则为上链且失败。

expired:是否过期失效。

如expired=true, success=false则表示该交易已经过期,需要重新提交。一般一个交易60秒失效。

如success=true则表示成功上链。

Example code:

import { Wallet } from '@project-serum/anchor'
import { Connection, Keypair, VersionedTransaction,LAMPORTS_PER_SOL } from '@solana/web3.js'
import bs58 from 'bs58';
import fetch from 'node-fetch'
import sleep from './util/sleep.js'
const inputToken = 'So11111111111111111111111111111111111111112'
const outputToken = '7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs'
const amount = '50000000'
const fromAddress = '2kpJ5QRh16aRQ4oLZ5LnucHFDAZtEFz6omqWWMzDSNrx'
const slippage = 0.5
// GMGN API 域名
const API_HOST = 'https://gmgn.ai'
async function main() {
  // 钱包初始化,如果用Phantom则忽略该步骤
  const wallet = new Wallet(Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY || '')))
  console.log(`wallet address: ${wallet.publicKey.toString()}`)
  // 获取quote以及待签名交易
  const quoteUrl = `${API_HOST}/defi/router/v1/sol/tx/get_swap_route?token_in_address=${inputToken}&token_out_address=${outputToken}&in_amount=${amount}&from_address=${fromAddress}&slippage=${slippage}`
  let route = await fetch(quoteUrl)
  route = await route.json()
  console.log(route)
  // 签名交易
  const swapTransactionBuf = Buffer.from(route.data.raw_tx.swapTransaction, 'base64')
  const transaction = VersionedTransaction.deserialize(swapTransactionBuf)
  transaction.sign([wallet.payer])
  const signedTx = Buffer.from(transaction.serialize()).toString('base64')
  console.log(signedTx)
  // 提交交易
  let res = await fetch(`${API_HOST}/defi/router/v1/sol/tx/submit_signed_transaction`,
    {
      method: 'POST',
      headers: {'content-type': 'application/json'},
      body: JSON.stringify(
        {
          "signed_tx": signedTx
        }
      )
    })
  res = await res.json()
  console.log(res)
  // 查询tx状态
  // 如果上链成功,则success返回true
  // 如果没上链,60秒就会返回expired=true
  while (true) {
    const hash =  res.data.hash
    const lastValidBlockHeight = route.data.raw_tx.lastValidBlockHeight
    const statusUrl = `${API_HOST}/defi/router/v1/sol/tx/get_transaction_status?hash=${hash}&last_valid_height=${lastValidBlockHeight}`
    let status = await fetch(statusUrl)
    status = await status.json()
    console.log(status)
    if (status && (status.data.success === true || status.data.expired === true))
      break
    await sleep(1000)
  }
}
main()

Last updated