You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenSea API V2创建Listing时签名无效,如何正确签名订单?

解决OpenSea Seaport订单签名无效问题

调用OpenSea测试网API创建Seaport挂单时,返回错误:

{"errors":["['Invalid order signature']"]}

以下是错误的签名实现分析及正确解决方案:

错误原因分析

  1. 第一种签名方式:直接将Order对象转为字符串后签名,完全不符合Seaport要求的EIP-712结构化签名规范,Seaport不会认可这种简单的字符串哈希签名。
  2. 第二种签名方式:虽然尝试引入EIP-712的domain和类型定义,但错误地将domain、类型和order对象转为字符串拼接后签名,这不是EIP-712的正确哈希方式,必须使用结构化数据编码生成签名哈希。

正确的Python签名实现

Seaport订单签名必须严格遵循EIP-712规范,使用web3库的结构化数据编码功能生成正确的消息哈希后再签名。同时要注意:order参数中所有数值类型(如startTime、salt、各类amount等)必须是整数类型,不能是字符串,否则编码会出错。

修正后的完整代码

import requests
from web3.auto import w3
from eth_account.messages import encode_structured_data
import time


def create_order_model():
    current_time = int(time.time())
    order = {
        "offerer": "0xd107AC5e5830BB95f880cA3b1270ccCdAA0A3c5e",
        "zone": "0x00000000e88fe2628ebc5da81d2b3cead633e89e",
        "zoneHash": "0x3000000000000000000000000000000000000000000000000000000000000000",
        "startTime": current_time,
        "endTime": current_time + 2629743,  # 当前时间+1个月(秒)
        "orderType": 2,
        "offer": [
            {
                "itemType": 2,
                "token": "0x45aeb17Db4dd06FF9Ca6cB1E37455AAF761Bdc14",
                "identifierOrCriteria": 1,
                "startAmount": 1,
                "endAmount": 1,
            },
        ],
        "consideration": [
            {
                "itemType": 0,
                "token": "0x0000000000000000000000000000000000000000",
                "identifierOrCriteria": 0,
                "startAmount": 9750000000000000000,
                "endAmount": 9750000000000000000,
                "recipient": "0xd107AC5e5830BB95f880cA3b1270ccCdAA0A3c5e",
            },
            {
                "itemType": 0,
                "token": "0x0000000000000000000000000000000000000000",
                "identifierOrCriteria": 0,
                "startAmount": 250000000000000000,
                "endAmount": 250000000000000000,
                "recipient": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
            },
        ],
        "totalOriginalConsiderationItems": 2,
        "salt": 12686911856931635052326433555881236148,
        "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000",
        "nonce": 0,
        "counter": 0
    }
    return order


def sign_order(order):
    private_key = "YOUR_PRIVATE_KEY"
    # EIP-712 domain数据
    domain = {
        "name": "Seaport",
        "version": "1.1",
        "chainId": 5,  # Goerli测试网链ID
        "verifyingContract": "0x00000000e88fe2628ebc5da81d2b3cead633e89e",  # Goerli的Seaport合约地址
    }

    # EIP-712类型定义
    types = {
        "OrderComponents": [
            {"name": "offerer", "type": "address"},
            {"name": "zone", "type": "address"},
            {"name": "offer", "type": "OfferItem[]"},
            {"name": "consideration", "type": "ConsiderationItem[]"},
            {"name": "orderType", "type": "uint8"},
            {"name": "startTime", "type": "uint256"},
            {"name": "endTime", "type": "uint256"},
            {"name": "zoneHash", "type": "bytes32"},
            {"name": "salt", "type": "uint256"},
            {"name": "conduitKey", "type": "bytes32"},
            {"name": "counter", "type": "uint256"},
        ],
        "OfferItem": [
            {"name": "itemType", "type": "uint8"},
            {"name": "token", "type": "address"},
            {"name": "identifierOrCriteria", "type": "uint256"},
            {"name": "startAmount", "type": "uint256"},
            {"name": "endAmount", "type": "uint256"},
        ],
        "ConsiderationItem": [
            {"name": "itemType", "type": "uint8"},
            {"name": "token", "type": "address"},
            {"name": "identifierOrCriteria", "type": "uint256"},
            {"name": "startAmount", "type": "uint256"},
            {"name": "endAmount", "type": "uint256"},
            {"name": "recipient", "type": "address"},
        ],
    }

    # 生成EIP-712结构化消息
    structured_msg = {
        "domain": domain,
        "types": types,
        "primaryType": "OrderComponents",
        "message": order
    }

    # 编码并签名
    encoded_msg = encode_structured_data(structured_msg)
    signed_message = w3.eth.account.sign_message(encoded_msg, private_key=private_key)
    return signed_message.signature.hex()


def main():
    url = "https://testnets-api.opensea.io/v2/orders/goerli/seaport/listings"
    headers = {
        "accept": "application/json",
        "content-type": "application/json"
    }

    order_parameters = create_order_model()
    signature = sign_order(order_parameters)

    params = {"parameters": order_parameters, "signature": signature}
    response = requests.post(url, headers=headers, json=params)
    print(response.text)


if __name__ == '__main__':
    main()

关键修正点

  1. 使用encode_structured_data替代encode_defunct,严格按照EIP-712规范编码订单数据
  2. 将order中所有数值类型字段从字符串改为整数,确保编码类型匹配
  3. 正确构建EIP-712的domain、types和message结构,而非字符串拼接

内容的提问来源于stack exchange,提问作者0xkornel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 23:45:44