2.5 验证 api key
前面几步验证的是分账合约和资金链路,走的都是 HashNut 控制台。这一步换成你自己的服务器来下单, 验证一键开户生成的 api key 能否正常创建订单、查询订单,以及能否收到 HashNut 的支付通知。
最省事的做法是跑一遍示范商城——它就是一个最小可用的接入样例,代码可以直接拿去改。
NOTE
示范商城有 Go 和 Java 两个版本,功能完全一致,选一个跑即可。 两者共用同一个 React 前端、同一份 migrate.sql,后端都监听 1800 端口,数据库都用 demo_shop。
2.5.1 环境要求
| 依赖 | 版本 | 说明 |
|---|---|---|
| Docker | 任意较新版本 | 用来跑 PostgreSQL,省去本机装数据库 |
| Node.js | 18+ | 前端 |
| Go | 1.21+ | 只有选 Go 版后端时需要 |
| Java + Maven | Java 11+ / Maven 3.6+ | 只有选 Java 版后端时需要 |
| 内网穿透工具 | —— | 仅本地开发需要,让 HashNut 能把支付通知发到你本机。 ngrok / frp / Cloudflare Tunnel 均可,见 附录 |
2.5.2 克隆代码
Go 版:
git clone https://github.com/nuttybounty/hashnut-demo-go.git
cd hashnut-demo-goJava 版:
git clone https://github.com/nuttybounty/hashnut-demo.git
cd hashnut-demoNOTE
Java 版的 HashNut SDK 通过 JitPack 自动拉取,不用手动安装。
2.5.3 用 Docker 起一个 PostgreSQL
docker run -d \
--name hashnut-demo-pg \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=demo_shop \
-p 5432:5432 \
postgres:16这几个参数对应的就是后端配置里的默认值,改了这里就要同步改后端配置:
| 参数 | 值 | 对应后端配置 |
|---|---|---|
| 用户名 | postgres(镜像默认) | user / username |
POSTGRES_PASSWORD | postgres | password |
POSTGRES_DB | demo_shop | dbname / url 里的库名 |
-p 5432:5432 | 映射到本机 5432 | host / port |
确认容器起来了:
docker exec hashnut-demo-pg pg_isready -U postgres输出 accepting connections 即可。
NOTE
POSTGRES_DB=demo_shop 会在容器首次启动时自动建库,所以不需要再手动 CREATE DATABASE。 如果你复用的是一个已存在的容器,这个环境变量不会生效,需要手动建库: docker exec -i hashnut-demo-pg psql -U postgres -c "CREATE DATABASE demo_shop;"
2.5.4 把开户信息填进 migrate.sql
打开仓库根目录的 migrate.sql,找到 t_hashnut_api_key 那段,把占位符换成 1.4 保存开户信息 里导出的值。
导出的 txt 末尾已经附了可以直接粘贴的 SQL,形如:
INSERT INTO t_hashnut_api_key (block_chain, splitter, access_key_id, secret_key) VALUES
('ETH', '0xbd09...fca', '01...YW', 'H1...Tt')
ON CONFLICT (block_chain) DO UPDATE SET
splitter = EXCLUDED.splitter,
access_key_id = EXCLUDED.access_key_id,
secret_key = EXCLUDED.secret_key;WARNING
migrate.sql 里自带那两行是占位示例(${split address} / secret-key),直接执行会导致下单验签失败。 一次一键开户只覆盖一条链,如果你要同时接 ETH 和 TRON,需要在客户端切换钱包各跑一次,把两段 SQL 都贴进来。
同时检查 t_coin_info 那段,确认里面的链和币种是你实际要用的——它决定了前端支付页面能选哪些链。
改完执行:
docker exec -i hashnut-demo-pg psql -U postgres -d demo_shop < migrate.sql验证数据进去了:
docker exec -i hashnut-demo-pg psql -U postgres -d demo_shop -c "select block_chain, splitter, access_key_id from t_hashnut_api_key;"2.5.5 配置并启动后端
Go 版:编辑 etc/application.yaml
server:
port: 1800
database:
host: "localhost"
port: 5432
user: "postgres"
password: "postgres"
dbname: "demo_shop"
sslmode: "disable"
hashnut:
testMode: false # 固定 false,即正式环境
baseURL: "" # 留空使用默认地址go run main.goJava 版:编辑 src/main/resources/application.yml
server:
port: 1800
spring:
datasource:
url: jdbc:postgresql://localhost:5432/demo_shop
username: postgres
password: postgres
hashnut:
test-mode: false # 固定 false,即正式环境
base-url: "" # 留空使用默认地址mvn spring-boot:run两者都启动在 http://localhost:1800。确认后端连上数据库了:
curl http://localhost:1800/api/chains应该返回你在 t_coin_info 里配的链和币种。
WARNING
testMode / test-mode 必须保持 false。设成 true 会让 SDK 指向另一个后端地址, 那里查不到你的 api key,下单会直接失败。
2.5.6 确认 notifyUrl 可达
notifyUrl 是 HashNut 主动来请求你的地址,必须公网可达。有公网服务器就直接用; 本地开发用内网穿透顶上,做法见 附录:本地调试让 notifyUrl 公网可达。
这里只要确认那个地址现在是通的:
curl https://你的公网地址/api/chains能返回链和币种即通。用 ngrok 免费版的话注意重启后地址会变,变了要回商户系统把 api key 的 notifyUrl 同步改掉,否则支付通知会发到失效地址上——表现就是"支付成功但订单状态一直不变"。
2.5.7 启动前端
前端是独立仓库,Go 版和 Java 版共用:
git clone https://github.com/nuttybounty/hashnut-demo-web.git
cd hashnut-demo-web
npm install
npm run dev启动在 http://localhost:5173,Vite 会自动把 /api 代理到 localhost:1800,不用额外配置跨域。
2.5.8 跑一遍完整支付
浏览器打开 http://localhost:5173,然后:
- 随便选一个商品,点 Pay with Crypto
- 选链和币种(就是
t_coin_info里配的那些) - 页面跳到 HashNut 支付页,用钱包完成支付
- 支付完成后自动跳回
http://localhost:5173/payment-result,显示支付成功
整条链路是这样走的:
浏览器 (localhost:5173)
→ POST /api/orders (Vite 代理到 localhost:1800,后端用 api key 调 HashNut 创建订单)
→ 跳转 HashNut 支付页
→ 用户链上支付
→ HashNut 服务器 → 内网穿透 → localhost:1800/api/notify (notifyUrl:后端收通知)
→ HashNut 支付页 → localhost:5173/payment-result?state=4 (callbackUrl:前端跳转)走通说明 api key 的下单、查询、回调通知都正常,这一节的目的就达到了。
出问题时先看哪里
| 现象 | 大概率原因 |
|---|---|
| 创建订单就失败,提示验签相关错误 | migrate.sql 里还是占位符,或 accessKey / secretKey 复制时漏了字符 |
| 提示 api key 不存在 | testMode / test-mode 没有设成 false |
| 前端支付页选不到链 | t_coin_info 没配那条链,或后端没连上数据库 |
| 支付成功但订单状态一直不变 | notifyUrl 不通:穿透工具没开、地址变了没同步、或把 notifyUrl 和 callbackUrl 填反了 |
| 下单被拒绝,提示 IP 相关 | api key 的 bindIp 不是 *,也不是你的出口 IP |
2.5.9 接下来
示范商城的完整接口清单、数据库表结构和部署说明见两个仓库的 README:
要把这套东西改成自己的业务,重点看后端三个地方:创建订单、查询订单、/api/notify 的验签与处理。 接口细节见 创建订单、查询订单、支付通知。