Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
bridge-backend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
movabridge
bridge-backend
Commits
40378b99
Commit
40378b99
authored
Nov 25, 2025
by
vicotor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update api
parent
5d68fb19
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
405 additions
and
10 deletions
+405
-10
api.md
api.md
+394
-0
controller.go
server/controller.go
+11
-10
No files found.
api.md
0 → 100644
View file @
40378b99
# REST API 接口文档
版本: v1 (前缀统一为
`/api/v1`
)
> 基础访问地址 (示例): `http://localhost:8080/api/v1` — 实际端口以运行配置为准 (`config.toml` 中的 `server.listen`).
## 统一返回格式
成功:
```
json
{
"code"
:
0
,
"msg"
:
"ok"
,
"data"
:
{
...具体数据...
}
}
```
失败:
```
json
{
"code"
:
1
,
"error"
:
"invalid param"
,
//
或其它错误信息
"data"
:
""
}
```
错误信息枚举 (
`constant/constant.go`
):
-
`invalid param`
-
`unsupported platform`
-
`internal error`
## 通用说明
-
所有地址字段需为合法 EVM 地址 (校验:
`common.IsHexAddress`
).
-
Token 地址建议全部使用小写十六进制,历史查询内部会转为小写。
-
金额字段
`amount`
/
`out_amount`
/
`balance`
/
`fee`
等均为字符串;单位(是否为最小单位 Wei)需与后端配置一致,当前实现没有转换逻辑,默认前端传最小单位。
## 数据模型 (节选自 `model/api/model.go`)
### 估算请求
跨链估算
`QuoteBridgeParam`
:
```
json
{
"from_chain_id"
:
61900
,
"to_chain_id"
:
56
,
"from_token"
:
"0x..."
,
"to_token"
:
"0x..."
,
"amount"
:
"<输入数量>"
,
"user"
:
"0x源地址"
,
"receiver"
:
"0x目标地址"
}
```
Swap 估算
`QuoteSwapParam`
:
```
json
{
"from_chain_id"
:
1
,
"to_chain_id"
:
137
,
"path"
:
{
"swap_from_token"
:
"0x源链用户输入 Token"
,
"bridge_from_token"
:
"0x源链中间桥接 Token"
,
"bridge_to_token"
:
"0x目标链中间桥接 Token"
,
"swap_to_token"
:
"0x目标链最终输出 Token"
},
"amount"
:
"<输入数量>"
,
"user"
:
"0x源地址"
,
"receiver"
:
"0x目标地址"
}
```
### 余额查询 `TokenBalanceQuery`:
```
json
{
"chain_id"
:
56
,
"user"
:
"0x地址"
,
"toke_list"
:
[
"0xTokenA"
,
"0xTokenB"
]
}
```
### 估算返回 `QuoteResult`
```
json
{
"to_contract"
:
"0x..."
,
//
目标链或合约地址
"out_amount"
:
"<输出数量>"
,
"payload"
:
"<执行交易所需数据, RLP/ABI 编码>"
}
```
### Token 余额返回 `TokenBalances`
```
json
{
"balances"
:
[
{
"name"
:
"TokenSymbol"
,
"decimals"
:
18
,
"balance"
:
"1230000000000000000"
,
"contract"
:
"0xTokenContract"
}
]
}
```
### 历史记录结构 `History`
```
json
{
"pending"
:
[
{
"tx_hash"
:
"0x...", "status"
:
"WaitConfirm"
}
],
"finish"
:
[
{
"tx_hash"
:
"0x...", "status"
:
"Executed"
}
]
}
```
状态枚举:
`NoProcess`
/
`WaitConfirm`
/
`Executed`
/
`Rejected`
。
---
## 接口列表与示例
### 1. 查询用户跨链历史
GET
`/user/history?address=<EVM地址>`
```
bash
curl
-G
http://localhost:8080/api/v1/user/history
\
--data-urlencode
"address=0x1234567890abcdef1234567890abcdef12345678"
```
### 2. 获取桥路由配置 (同 `/params` 数据)
GET
`/bridge/routers`
```
bash
curl
-X
GET http://localhost:8080/api/v1/bridge/routers
```
成功返回示例 (桥接配置
`BridgeConfig`
):
```
json
{
"code"
:
0
,
"data"
:
{
"chains"
:
{
"BNB Smart Chain Mainnet"
:
{
"chain"
:
"BNB Smart Chain Mainnet"
,
"chain_id"
:
56
,
"contract"
:
"0x214c0b3d19ad265c258dea678cf1f5a63499c0d9"
,
"support_tokens"
:
{
"USD1"
:
{
"token_contract"
:
"0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d"
,
"token_symbol"
:
"USD1"
,
"bridge_tokens"
:
[
{
"token_contract"
:
"0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d"
,
"to_chain_id"
:
61900
,
"to_token"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"to_token_symbol"
:
"USD1"
,
"fee"
:
"0"
,
"max_limit"
:
"1000000000000000000000000"
}
]
},
"USDT"
:
{
"token_contract"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"token_symbol"
:
"USDT"
,
"bridge_tokens"
:
[
{
"token_contract"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"to_chain_id"
:
61900
,
"to_token"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"to_token_symbol"
:
"USD1"
,
"fee"
:
"0"
,
"max_limit"
:
"1000000000000000000000000"
}
]
}
},
"explorer_url"
:
"https://bscscan.com"
,
"rpc"
:
"https://binance.llamarpc.com"
},
"Mova Mainnet"
:
{
"chain"
:
"Mova Mainnet"
,
"chain_id"
:
61900
,
"contract"
:
"0x214c0b3d19ad265c258dea678cf1f5a63499c0d9"
,
"support_tokens"
:
{
"USD1"
:
{
"token_contract"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"token_symbol"
:
"USD1"
,
"bridge_tokens"
:
[
{
"token_contract"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"to_chain_id"
:
56
,
"to_token"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"to_token_symbol"
:
"USDT"
,
"fee"
:
"20000000000000000"
,
"max_limit"
:
"1000000000000000000000000"
}
]
}
},
"explorer_url"
:
"https://scan.movachain.com"
,
"rpc"
:
"https://rpc.movachain.com"
}
}
},
"msg"
:
"ok"
}
```
### 3. 查询桥场景下用户 Token 余额
POST
`/bridge/balance`
```
bash
curl
-X
POST http://localhost:8080/api/v1/bridge/balance
\
-H
"Content-Type: application/json"
\
-d
'{
"chain_id": 61900,
"user": "0x88395111ab1586a4030dac62a183542762929bbc",
"toke_list": ["0x57b84a31e00ef4378e6b2d30703b73d02aee13f8", "0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"]
}'
```
成功返回示例 (Token 余额
`TokenBalances`
):
```
json
{
"code"
:
0
,
"data"
:
{
"balances"
:
[
{
"name"
:
"USD1"
,
"decimals"
:
18
,
"balance"
:
"0"
,
"contract"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
},
{
"name"
:
"WMOVA"
,
"decimals"
:
18
,
"balance"
:
"0"
,
"contract"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
}
]
},
"msg"
:
"ok"
}
```
### 4. 获取跨链报价
POST
`/bridge/quote`
请求体:
`QuoteBridgeParam`
```
bash
curl
-X
POST http://localhost:8080/api/v1/bridge/quote
\
-H
"Content-Type: application/json"
\
-d
'{
"from_chain_id": 61900,
"to_chain_id": 56,
"from_token": "0x57b84a31e00ef4378e6b2d30703b73d02aee13f8",
"to_token": "0x55d398326f99059ff775485246999027b3197955",
"amount": "1000000000000000000",
"user": "0x88395111ab1586a4030dac62a183542762929bbc",
"receiver": "0x88395111ab1586a4030dac62a183542762929bbc"
}'
```
### 5. 获取全部 Swap 路由配置
GET
`/swap/routers`
```
bash
curl
-X
GET http://localhost:8080/api/v1/swap/routers
```
成功返回示例:
```
json
{
"code"
:
0
,
"data"
:
{
"56"
:
{
"chain"
:
"BNB Smart Chain Mainnet"
,
"chain_id"
:
56
,
"contract"
:
"0x214c0b3d19ad265c258dea678cf1f5a63499c0d9"
,
"support_tokens"
:
{
"0x55d398326f99059ff775485246999027b3197955"
:
{
"token_contract"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"token_symbol"
:
"USDT"
,
"swap_tokens"
:
{
"61900"
:
{
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
:
{
"to_chain_id"
:
61900
,
"to_token"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
,
"to_token_symbol"
:
"WMOVA"
,
"path"
:
{
"swap_from_token"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"bridge_from_token"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"bridge_to_token"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"swap_to_token"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
}
}
}
}
},
"0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d"
:
{
"token_contract"
:
"0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d"
,
"token_symbol"
:
"USD1"
,
"swap_tokens"
:
{
"61900"
:
{
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
:
{
"to_chain_id"
:
61900
,
"to_token"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
,
"to_token_symbol"
:
"WMOVA"
,
"path"
:
{
"swap_from_token"
:
"0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d"
,
"bridge_from_token"
:
"0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d"
,
"bridge_to_token"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"swap_to_token"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
}
}
}
}
}
},
"explorer_url"
:
"https://bscscan.com"
,
"rpc"
:
"https://binance.llamarpc.com"
},
"61900"
:
{
"chain"
:
"Mova Mainnet"
,
"chain_id"
:
61900
,
"contract"
:
"0x214C0b3d19ad265c258DeA678Cf1f5a63499c0d9"
,
"support_tokens"
:
{
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
:
{
"token_contract"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
,
"token_symbol"
:
"WMOVA"
,
"swap_tokens"
:
{
"56"
:
{
"0x55d398326f99059ff775485246999027b3197955"
:
{
"to_chain_id"
:
56
,
"to_token"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"to_token_symbol"
:
"USDT"
,
"path"
:
{
"swap_from_token"
:
"0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
,
"bridge_from_token"
:
"0x57b84a31e00ef4378e6b2d30703b73d02aee13f8"
,
"bridge_to_token"
:
"0x55d398326f99059ff775485246999027b3197955"
,
"swap_to_token"
:
"0x55d398326f99059ff775485246999027b3197955"
}
}
}
}
}
},
"explorer_url"
:
"https://scan.movachain.com"
,
"rpc"
:
"https://rpc.movachain.com"
}
},
"msg"
:
"ok"
}
```
### 6. 查询 Swap 场景下 Token 余额
POST
`/swap/balance`
请求体:
`TokenBalanceQuery`
```
bash
curl
-X
POST http://localhost:8080/api/v1/swap/balance
\
-H
"Content-Type: application/json"
\
-d
'{
"chain_id": 61900,
"user": "0x88395111ab1586a4030dac62a183542762929bbc",
"toke_list": ["0x57b84a31e00ef4378e6b2d30703b73d02aee13f8", "0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"]
}'
```
### 7. 预估Swap之后的数量
POST
`/swap/quote`
请求体:
`QuoteSwapParam`
```
bash
curl
-X
POST http://localhost:8080/api/v1/swap/quote
\
-H
"Content-Type: application/json"
\
-d
'{
"from_chain_id": 56,
"to_chain_id": 61900,
"path": {
"swap_from_token": "0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d",
"bridge_from_token": "0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d",
"bridge_to_token": "0x57b84a31e00ef4378e6b2d30703b73d02aee13f8",
"swap_to_token": "0x6cd7919b80a9cfc8d2c6cfa363af70040a48f10e"
},
"amount": "250000000000000000",
"user": "0x88395111ab1586a4030dac62a183542762929bbc",
"receiver": "0x88395111ab1586a4030dac62a183542762929bbc"
}'
```
---
## 响应示例: 报价成功
```
json
{
"code"
:
0
,
"msg"
:
"ok"
,
"data"
:
{
"to_contract"
:
"0xTargetContract"
,
"out_amount"
:
"980000000000000000"
,
"payload"
:
"0xabcdef..."
}
}
```
## 响应示例: 参数错误
```
json
{
"code"
:
1
,
"error"
:
"invalid param"
,
"data"
:
""
}
```
server/controller.go
View file @
40378b99
...
@@ -71,16 +71,17 @@ func bridgeBalance(c *gin.Context) {
...
@@ -71,16 +71,17 @@ func bridgeBalance(c *gin.Context) {
return
return
}
}
var
queryParam
apiModel
.
TokenBalanceQuery
var
queryParam
apiModel
.
TokenBalanceQuery
if
err
:=
c
.
ShouldBindQuery
(
&
queryParam
);
err
!=
nil
{
// Try JSON first, then fallback to query binding for backward compatibility
log
.
Errorf
(
"bind query param error: %v"
,
err
)
if
err
:=
c
.
ShouldBindJSON
(
&
queryParam
);
err
!=
nil
{
log
.
Errorf
(
"bind param error json:%v"
,
err
)
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
return
return
}
}
if
!
common
.
IsHexAddress
(
queryParam
.
User
)
{
if
!
common
.
IsHexAddress
(
queryParam
.
User
)
{
log
.
Errorf
(
"invalid user address: %v"
,
queryParam
.
User
)
log
.
Errorf
(
"invalid user address: %v"
,
queryParam
.
User
)
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
return
}
}
// get all tokens
balances
,
err
:=
_querier
.
GetTokenBalance
(
queryParam
.
ChainId
,
queryParam
.
User
,
queryParam
.
TokeList
)
balances
,
err
:=
_querier
.
GetTokenBalance
(
queryParam
.
ChainId
,
queryParam
.
User
,
queryParam
.
TokeList
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Errorf
(
"get bridge balance error: %v"
,
err
)
log
.
Errorf
(
"get bridge balance error: %v"
,
err
)
...
@@ -97,8 +98,8 @@ func bridgeQuote(c *gin.Context) {
...
@@ -97,8 +98,8 @@ func bridgeQuote(c *gin.Context) {
return
return
}
}
var
queryParam
apiModel
.
QuoteBridgeParam
var
queryParam
apiModel
.
QuoteBridgeParam
if
err
:=
c
.
ShouldBind
Query
(
&
queryParam
);
err
!=
nil
{
if
err
:=
c
.
ShouldBind
JSON
(
&
queryParam
);
err
!=
nil
{
log
.
Errorf
(
"bind
query param error:
%v"
,
err
)
log
.
Errorf
(
"bind
param error json:
%v"
,
err
)
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
return
return
}
}
...
@@ -143,16 +144,16 @@ func swapBalance(c *gin.Context) {
...
@@ -143,16 +144,16 @@ func swapBalance(c *gin.Context) {
return
return
}
}
var
queryParam
apiModel
.
TokenBalanceQuery
var
queryParam
apiModel
.
TokenBalanceQuery
if
err
:=
c
.
ShouldBind
Query
(
&
queryParam
);
err
!=
nil
{
if
err
:=
c
.
ShouldBind
JSON
(
&
queryParam
);
err
!=
nil
{
log
.
Errorf
(
"bind
query param error:
%v"
,
err
)
log
.
Errorf
(
"bind
param error json:
%v"
,
err
)
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
return
return
}
}
if
!
common
.
IsHexAddress
(
queryParam
.
User
)
{
if
!
common
.
IsHexAddress
(
queryParam
.
User
)
{
log
.
Errorf
(
"invalid user address: %v"
,
queryParam
.
User
)
log
.
Errorf
(
"invalid user address: %v"
,
queryParam
.
User
)
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
return
}
}
// get all tokens
balances
,
err
:=
_querier
.
GetTokenBalance
(
queryParam
.
ChainId
,
queryParam
.
User
,
queryParam
.
TokeList
)
balances
,
err
:=
_querier
.
GetTokenBalance
(
queryParam
.
ChainId
,
queryParam
.
User
,
queryParam
.
TokeList
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Errorf
(
"get swap balance error: %v"
,
err
)
log
.
Errorf
(
"get swap balance error: %v"
,
err
)
...
@@ -169,8 +170,8 @@ func swapQuote(c *gin.Context) {
...
@@ -169,8 +170,8 @@ func swapQuote(c *gin.Context) {
return
return
}
}
var
queryParam
apiModel
.
QuoteSwapParam
var
queryParam
apiModel
.
QuoteSwapParam
if
err
:=
c
.
ShouldBind
Query
(
&
queryParam
);
err
!=
nil
{
if
err
:=
c
.
ShouldBind
JSON
(
&
queryParam
);
err
!=
nil
{
log
.
Errorf
(
"bind
query param error:
%v"
,
err
)
log
.
Errorf
(
"bind
param error json:
%v"
,
err
)
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
c
.
JSON
(
200
,
withError
(
constant
.
InvalidParam
))
return
return
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment