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

✅ 若通过审核，GMGN会将API Key发送至你填写的邮箱\
❌ 若未通过审核，GMGN将不会发送任何信息通知

### 鉴权

* GMGN为我们的专业用户提供 SOL/BSC/Base/ETH 交易API，能否通过的唯一标准是你在GMGN是否有足够的交易量。审核将在提交后24小时内完成
* 访问GMGN Trade Api需申请使用权限，请填写以下google表单申请，<https://forms.gle/CWABDLRe8twvygvy5>
* 审核通过后GMGN会分配一个Api Key至你的邮箱，访问接口需将Api Key带入header中，header name:  `x-route-key`
* 每个Api Key限频5s调用一次

## 1.**查询路由接入点(支持防夹)：**

```javascript
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: 申请通过后发放至邮箱**

**输入参数：**

<table><thead><tr><th width="230">参数名</th><th width="126">类型</th><th>说明</th></tr></thead><tbody><tr><td>token_in_address</td><td>string</td><td>兑换要花的币，输入代币地址，例如： So11111111111111111111111111111111111111112</td></tr><tr><td>token_out_address</td><td>string</td><td>兑换目标币地址，例如：7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs</td></tr><tr><td>in_amount</td><td>string</td><td>最小单位lamports，100000000=0.1SOL</td></tr><tr><td>from_address</td><td>string</td><td>发起交易钱包地址，例如：2kpJ5QRh16aRQ4oLZ5LnucHFDAZtEFz6omqWWMzDSNrx</td></tr><tr><td>slippage</td><td>float</td><td>滑点，%之上的数值，比如10表示10%</td></tr><tr><td>swap_mode</td><td>string</td><td>ExactIn或者ExactOut，默认不传则是ExactIn</td></tr><tr><td>fee</td><td>float</td><td>网络和节点优先费。例如0.006, 单位SOL。GMGN会自动分配节点贿赂小费和网络优先费。 如果开防夹，fee需要至少 0.002</td></tr><tr><td>is_anti_mev</td><td>bool</td><td>可选，防夹交易时设为true</td></tr><tr><td>partner</td><td>string</td><td>可选，合作伙伴来源名称</td></tr></tbody></table>

返回参数：

<table><thead><tr><th width="129">参数名</th><th width="229">类型</th><th>说明</th></tr></thead><tbody><tr><td>code</td><td>int</td><td>错误码，0</td></tr><tr><td>msg</td><td>string</td><td>结果描述，success</td></tr><tr><td>data</td><td>Object</td><td><p>{</p><p>     quote: {</p><p>       inputMint: 'So11111111111111111111111111111111111111112',</p><p>       inAmount: '50000000',</p><p>       outputMint: '7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs',</p><p>       outAmount: '77920478752',</p><p>       otherAmountThreshold: '77530876359',</p><p>       swapMode: 'ExactIn',</p><p>       slippageBps: 50,</p><p>       platformFee: null,</p><p>       priceImpactPct: '0',</p><p>       routePlan: [Array],</p><p>       contextSlot: 240893434,</p><p>       timeTaken: 0.04250061</p><p>     },</p><p>     raw_tx: {</p><p>       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=',</p><p>       lastValidBlockHeight: 221852977,</p><p>       prioritizationFeeLamports: 9601,</p><p>       recentBlockhash: 'HThJomQ74BKBYYfFewg9m5MrRwAsHjrpuTwEcohxpAEW'</p><p>     }</p><p>   }</p></td></tr></tbody></table>

返回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 类型说明：

<figure><img src="/files/AidHd1lrL2AO2hwgzPh0" alt=""><figcaption></figcaption></figure>

返回data.raw\_tx字段说明：

<table data-header-hidden><thead><tr><th width="266"></th><th width="153"></th><th></th></tr></thead><tbody><tr><td>参数名</td><td>类型</td><td>说明</td></tr><tr><td>swapTransaction</td><td>string</td><td>base64编码的待签名tx</td></tr><tr><td>lastValidBlockHeight</td><td>int</td><td>打包待签名tx时的区块高度，221852977</td></tr><tr><td>recentBlockhash</td><td>string</td><td>打包待签名tx时的最新上链的块hash，HThJomQ74BKBYYfFewg9m5MrRwAsHjrpuTwEcohxpAEW</td></tr><tr><td>prioritizationFeeLamports</td><td>int</td><td>推荐优先费用，最小单位lamports，9601</td></tr></tbody></table>

## 2. 提交交易接入点

```javascript
https://gmgn.ai/txproxy/v1/send_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")`

请求参数：

<table data-header-hidden><thead><tr><th width="163.63018798828125"></th><th width="163.140625"></th><th></th></tr></thead><tbody><tr><td><strong>参数名</strong></td><td><strong>类型</strong></td><td><strong>说明</strong></td></tr><tr><td>chain</td><td>string</td><td>目前仅支持SOL链</td></tr><tr><td>signedTx</td><td>string</td><td>签名后的交易，使用base64 encode之后的字串</td></tr><tr><td>isAntiMev</td><td>bool</td><td>是否防夾</td></tr></tbody></table>

返回字段：

<table data-header-hidden><thead><tr><th width="159.0625"></th><th width="164.76171875"></th><th></th></tr></thead><tbody><tr><td><strong>参数名</strong></td><td><strong>类型</strong></td><td><strong>说明</strong></td></tr><tr><td>code</td><td>int</td><td>错误码，0</td></tr><tr><td>msg</td><td>string</td><td>错误信息，success</td></tr><tr><td>data</td><td>Object</td><td><p>{<br>"hash": "2WN388zpPEy5zZR1uDGRqYbWotHFWo2Y6atAwfLGwUvDEi8LGk93X9S5pimNMv4uQgpJNf6SFQbZF83XbvgTuikj"<br>"resArr": [<br>{<br>"hash": "2WN388zpPEy5zZR1uDGRqYbWotHFWo2Y6atAwfLGwUvDEi8LGk93X9S5pimNMv4uQgpJNf6SFQbZF83XbvgTuikj",<br>"err": null<br>},<br>{<br>"hash": "2WN388zpPEy5zZR1uDGRqYbWotHFWo2Y6atAwfLGwUvDEi8LGk93X9S5pimNMv4uQgpJNf6SFQbZF83XbvgTuikj",<br>"err": null<br>}<br>]<br>}</p><p> </p></td></tr></tbody></table>

## 3. 查询交易状态接入点：

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

**请求方式：GET**

**请求参数：**

<table><thead><tr><th width="199">参数名</th><th width="150">类型</th><th>说明</th></tr></thead><tbody><tr><td>hash</td><td>string</td><td>提交完交易后返回的hash，例如3Qr9Kb8XfQiTa2E4butFRdVgWb9jTorcQaCPx3zx9fETyZhnffVdjagGU7PkwJVX8X9Js4xvUjybCaNjvFGozoLR</td></tr><tr><td>last_valid_height</td><td>int</td><td>路由接口返回的待签名交易打包时的块高度，例如221852977</td></tr></tbody></table>

**返回字段：**

<table><thead><tr><th width="199">参数名</th><th width="154">类型</th><th>说明</th></tr></thead><tbody><tr><td>code</td><td>int</td><td>0</td></tr><tr><td>msg</td><td>string</td><td>success</td></tr><tr><td>data</td><td>Object</td><td>{ success: true, expired: false }</td></tr></tbody></table>

**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}/txproxy/v1/send_transaction`,
    {
      method: 'POST',
      headers: {'content-type': 'application/json'},
      body: JSON.stringify(
        {
          "chain": "sol",
          "signedTx": 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()

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.gmgn.ai/cn/he-zuo-api-ji-cheng-gmgn-solana-jiao-yi-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
