97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package genex
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"math/big"
|
||
"strings"
|
||
|
||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||
"github.com/ethereum/go-ethereum/common"
|
||
"github.com/ethereum/go-ethereum/core/types"
|
||
)
|
||
|
||
// Settlement 合约 ABI(executeSwap 函数签名)
|
||
const settlementABIJSON = `[{"name":"executeSwap","type":"function","inputs":[{"name":"tokenId","type":"uint256"},{"name":"buyer","type":"address"},{"name":"seller","type":"address"},{"name":"price","type":"uint256"},{"name":"stablecoin","type":"address"}],"outputs":[]}]`
|
||
|
||
// SettlementContractAddress 默认 Settlement 合约地址(可通过配置覆盖)
|
||
var SettlementContractAddress = common.HexToAddress("0x0000000000000000000000000000000000000004")
|
||
|
||
// TxReceipt 交易回执
|
||
type TxReceipt struct {
|
||
TxHash string `json:"txHash"`
|
||
BlockNumber int64 `json:"blockNumber"`
|
||
GasUsed uint64 `json:"gasUsed"`
|
||
Status uint64 `json:"status"` // 1=success, 0=failed
|
||
}
|
||
|
||
// ExecuteSwap 构造+签名+广播券原子交换交易
|
||
func (c *Client) ExecuteSwap(params SwapParams, signer Signer) (*TxReceipt, error) {
|
||
parsedABI, err := abi.JSON(strings.NewReader(settlementABIJSON))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("parse settlement ABI: %w", err)
|
||
}
|
||
|
||
calldata, err := parsedABI.Pack("executeSwap",
|
||
params.TokenID,
|
||
params.Buyer,
|
||
params.Seller,
|
||
params.Price,
|
||
params.Stablecoin,
|
||
)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("pack executeSwap: %w", err)
|
||
}
|
||
|
||
// 获取 nonce
|
||
nonce, err := c.ethClient.PendingNonceAt(context.Background(), signer.GetAddress())
|
||
if err != nil {
|
||
return nil, fmt.Errorf("get nonce: %w", err)
|
||
}
|
||
|
||
// 获取 gas price
|
||
gasPrice, err := c.ethClient.SuggestGasPrice(context.Background())
|
||
if err != nil {
|
||
return nil, fmt.Errorf("suggest gas price: %w", err)
|
||
}
|
||
|
||
// 构造交易
|
||
tx := types.NewTransaction(
|
||
nonce,
|
||
SettlementContractAddress,
|
||
big.NewInt(0),
|
||
uint64(300000), // gas limit
|
||
gasPrice,
|
||
calldata,
|
||
)
|
||
|
||
// 签名
|
||
signedBytes, err := signer.SignTransaction(tx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("sign transaction: %w", err)
|
||
}
|
||
|
||
// 广播
|
||
var signedTx types.Transaction
|
||
if err := signedTx.UnmarshalBinary(signedBytes); err != nil {
|
||
return nil, fmt.Errorf("unmarshal signed tx: %w", err)
|
||
}
|
||
|
||
if err := c.ethClient.SendTransaction(context.Background(), &signedTx); err != nil {
|
||
return nil, fmt.Errorf("send transaction: %w", err)
|
||
}
|
||
|
||
// 等待回执
|
||
receipt, err := c.ethClient.TransactionReceipt(context.Background(), signedTx.Hash())
|
||
if err != nil {
|
||
return nil, fmt.Errorf("get receipt: %w", err)
|
||
}
|
||
|
||
return &TxReceipt{
|
||
TxHash: signedTx.Hash().Hex(),
|
||
BlockNumber: receipt.BlockNumber.Int64(),
|
||
GasUsed: receipt.GasUsed,
|
||
Status: receipt.Status,
|
||
}, nil
|
||
}
|