Type/to search
Built-in Functions
Global
Version
Sleep
IsVirtual
Mail
Mail_Go
SetErrorFilter
GetPid
GetLastError
GetCommand
GetMeta
Dial
HttpQuery
HttpQuery_Go
Encode
UnixNano
Unix
GetOS
MD5
DBExec
UUID
EventLoop
__Serve
_G
_D
_N
_C
_Cross
JSON.parse
JSON.stringify
SetChannelData
GetChannelData
Log
Market
Trade
Account
Futures
NetSettings
Threads
threading
Thread
getThread
mainThread
currentThread
Lock
Condition
Event
Dict
pending
Thread
ThreadLock
ThreadEvent
ThreadCondition
ThreadDict
Web3
TA
Talib
talib.CDL2CROWS
talib.CDL3BLACKCROWS
talib.CDL3INSIDE
talib.CDL3LINESTRIKE
talib.CDL3OUTSIDE
talib.CDL3STARSINSOUTH
talib.CDL3WHITESOLDIERS
talib.CDLABANDONEDBABY
talib.CDLADVANCEBLOCK
talib.CDLBELTHOLD
talib.CDLBREAKAWAY
talib.CDLCLOSINGMARUBOZU
talib.CDLCONCEALBABYSWALL
talib.CDLCOUNTERATTACK
talib.CDLDARKCLOUDCOVER
talib.CDLDOJI
talib.CDLDOJISTAR
talib.CDLDRAGONFLYDOJI
talib.CDLENGULFING
talib.CDLEVENINGDOJISTAR
talib.CDLEVENINGSTAR
talib.CDLGAPSIDESIDEWHITE
talib.CDLGRAVESTONEDOJI
talib.CDLHAMMER
talib.CDLHANGINGMAN
talib.CDLHARAMI
talib.CDLHARAMICROSS
talib.CDLHIGHWAVE
talib.CDLHIKKAKE
talib.CDLHIKKAKEMOD
talib.CDLHOMINGPIGEON
talib.CDLIDENTICAL3CROWS
talib.CDLINNECK
talib.CDLINVERTEDHAMMER
talib.CDLKICKING
talib.CDLKICKINGBYLENGTH
talib.CDLLADDERBOTTOM
talib.CDLLONGLEGGEDDOJI
talib.CDLLONGLINE
talib.CDLMARUBOZU
talib.CDLMATCHINGLOW
talib.CDLMATHOLD
talib.CDLMORNINGDOJISTAR
talib.CDLMORNINGSTAR
talib.CDLONNECK
talib.CDLPIERCING
talib.CDLRICKSHAWMAN
talib.CDLRISEFALL3METHODS
talib.CDLSEPARATINGLINES
talib.CDLSHOOTINGSTAR
talib.CDLSHORTLINE
talib.CDLSPINNINGTOP
talib.CDLSTALLEDPATTERN
talib.CDLSTICKSANDWICH
talib.CDLTAKURI
talib.CDLTASUKIGAP
talib.CDLTHRUSTING
talib.CDLTRISTAR
talib.CDLUNIQUE3RIVER
talib.CDLUPSIDEGAP2CROWS
talib.CDLXSIDEGAP3METHODS
talib.AD
talib.ADOSC
talib.OBV
talib.ACOS
talib.ASIN
talib.ATAN
talib.CEIL
talib.COS
talib.COSH
talib.EXP
talib.FLOOR
talib.LN
talib.LOG10
talib.SIN
talib.SINH
talib.SQRT
talib.TAN
talib.TANH
talib.MAX
talib.MAXINDEX
talib.MIN
talib.MININDEX
talib.MINMAX
talib.MINMAXINDEX
talib.SUM
talib.HT_DCPERIOD
talib.HT_DCPHASE
talib.HT_PHASOR
talib.HT_SINE
talib.HT_TRENDMODE
talib.ATR
talib.NATR
talib.TRANGE
talib.BBANDS
talib.DEMA
talib.EMA
talib.HT_TRENDLINE
talib.KAMA
talib.MA
talib.MAMA
talib.MIDPOINT
talib.MIDPRICE
talib.SAR
talib.SAREXT
talib.SMA
talib.T3
talib.TEMA
talib.TRIMA
talib.WMA
talib.LINEARREG
talib.LINEARREG_ANGLE
talib.LINEARREG_INTERCEPT
talib.LINEARREG_SLOPE
talib.STDDEV
talib.TSF
talib.VAR
talib.ADX
talib.ADXR
talib.APO
talib.AROON
talib.AROONOSC
talib.BOP
talib.CCI
talib.CMO
talib.DX
talib.MACD
talib.MACDEXT
talib.MACDFIX
talib.MFI
talib.MINUS_DI
talib.MINUS_DM
talib.MOM
talib.PLUS_DI
talib.PLUS_DM
talib.PPO
talib.ROC
talib.ROCP
talib.ROCR
talib.ROCR100
talib.RSI
talib.STOCH
talib.STOCHF
talib.STOCHRSI
talib.TRIX
talib.ULTOSC
talib.WILLR
talib.AVGPRICE
talib.MEDPRICE
talib.TYPPRICE
talib.WCLPRICE
OS
Structures
Built-in Variables

The exchange.IO("sign", ...) calling method is used to sign a 32-byte hash with a secp256k1 private key and returns signature data such as r, s, and v. It is suitable for scenarios that require off-chain signing, such as EIP-712 structured data signing (e.g., ERC-20 Permit approvals, 1inch limit orders).

exchange.IO(k, hash)
exchange.IO(k, hash, key)

Examples

Taking the ERC-20 Permit (EIP-2612) authorization signature for USDC on Ethereum mainnet as an example: first read the on-chain parameters, use exchange.IO("encode", ...) and exchange.IO("hash", "keccak256", ...) to compute the EIP-712 digest, then use exchange.IO("sign", ...) to sign the digest, and finally simulate a call to the permit method of the USDC contract via eth_call to verify the signature (simulation only; no transaction is sent and no gas is consumed). Return values of type bytes32 are returned as byte arrays; the example uses the bytesToHex function to convert them to hexadecimal strings.

javascript
// Sign an EIP-2612 Permit for USDC on Ethereum mainnet, and have the USDC contract verify the signature via eth_call (simulation only; no transaction is sent and no gas is consumed) var USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // USDC contract address on Ethereum mainnet var SPENDER = "0x1111111254EEB25477B68fb85Ed929f73A960582" // Spender address (example: 1inch Router v5) var VALUE = "1000000" // Allowance: 1 USDC (6 decimals) // keccak256 → hex string prefixed with 0x. fmt = "raw" (treat as string) or "hex" (treat as hexadecimal data) function keccak(fmt, data) { return "0x" + String(exchange.IO("hash", "keccak256", fmt, "hex", data)).replace(/^0x/, "") } function strip0x(h) { return String(h).replace(/^0x/, "") } // Return values of type bytesN are byte arrays (consistent with previous versions); convert them to a hex string prefixed with 0x here function bytesToHex(v) { if (typeof v === "string") return "0x" + strip0x(v).toLowerCase() return "0x" + v.map(function (b) { return ("0" + b.toString(16)).slice(-2) }).join("") } // Function selector + standard ABI-encoded arguments → calldata function calldata(signature, types, values) { var args = exchange.IO.apply(exchange, ["encode", types].concat(values)) return keccak("raw", signature).slice(0, 10) + strip0x(args) } // eth_call simulation: returns true on success, or the error reason on revert function simulate(data) { var r = exchange.IO("api", "eth", "eth_call", { from: SPENDER, to: USDC, data: data }, "latest") return r === null ? GetLastError() : true } function main() { // 1. Register the required ABI fragments and read the on-chain parameters exchange.IO("abi", USDC, JSON.stringify([ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] }, { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] }, { type: "function", name: "nonces", stateMutability: "view", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }] }, { type: "function", name: "DOMAIN_SEPARATOR", stateMutability: "view", inputs: [], outputs: [{ type: "bytes32" }] } ])) var owner = exchange.IO("address") var name = exchange.IO("api", USDC, "name") var version = exchange.IO("api", USDC, "version") var nonce = exchange.IO("api", USDC, "nonces", owner) var chainId = parseInt(exchange.IO("api", "eth", "eth_chainId"), 16) var deadline = Math.floor(Date.now() / 1000) + 3600 Log("owner:", owner, "| token:", name, "v" + version, "| nonce:", nonce, "| chainId:", chainId) // 2. Compute the EIP-712 domain separator and compare it with the value returned by the contract's DOMAIN_SEPARATOR() var domainSeparator = keccak("hex", exchange.IO("encode", "bytes32,bytes32,bytes32,uint256,address", keccak("raw", "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak("raw", name), keccak("raw", version), chainId, USDC)) var onchain = bytesToHex(exchange.IO("api", USDC, "DOMAIN_SEPARATOR")) Log("domainSeparator:", domainSeparator, domainSeparator === onchain ? "matches on-chain value" : "does not match on-chain value: " + onchain) // 3. Permit struct hash → EIP-712 digest → signature var structHash = keccak("hex", exchange.IO("encode", "bytes32,address,address,uint256,uint256,uint256", keccak("raw", "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), owner, SPENDER, VALUE, nonce, deadline)) var digest = keccak("hex", "1901" + strip0x(domainSeparator) + strip0x(structHash)) var sig = exchange.IO("sign", digest) Log("digest:", digest) Log("sign:", sig) // 4. Have the USDC contract verify the signature: permit(owner, spender, value, deadline, v, r, s) Log("permit(v,r,s) simulation:", simulate(calldata( "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)", "address,address,uint256,uint256,uint8,bytes32,bytes32", [owner, SPENDER, VALUE, deadline, sig.v, sig.r, sig.s]))) // USDC v2.2 also provides an overloaded method that accepts a bytes-type signature: permit(owner, spender, value, deadline, signature) Log("permit(bytes) simulation:", simulate(calldata( "permit(address,address,uint256,uint256,bytes)", "address,address,uint256,uint256,bytes", [owner, SPENDER, VALUE, deadline, sig.signature]))) // 5. Negative case: after tampering with the v value, the contract should reject the signature Log("simulation after tampering with v:", simulate(calldata( "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)", "address,address,uint256,uint256,uint8,bytes32,bytes32", [owner, SPENDER, VALUE, deadline, sig.v === 27 ? 28 : 27, sig.r, sig.s]))) }

Returns

TypeDescription

object

The exchange.IO("sign", ...) function returns a signature object containing the following fields: r (32 bytes, hexadecimal string), s (32 bytes, hexadecimal string), v (numeric value, 27 or 28), signature (65 bytes r‖s‖v, hexadecimal string), and vs (EIP-2098 compact signature, 32 bytes, hexadecimal string). Returns a null value if the call fails.

Arguments

NameTypeRequiredDescription

k

string

Yes

The k parameter is used to set the function of the exchange.IO() function. Setting it to "sign" indicates that the function is used to sign a hash.

hash

string

Yes

The hash parameter is the 32-byte hash to be signed, formatted as a hexadecimal string; the 0x prefix is optional. This function does not hash the hash again, so the EIP-712 digest must be computed in advance. Please refer to the example.

key

string

No

The key parameter is used to specify the private key used for signing. If it is not passed, the private key configured for the exchange exchange object is used.

Remarks

EIP-712 signing can be used directly by passing in domain, types, and message, with no need to compute the digest yourself; EIP-191 message signing uses.

The returned s is always a low-s value (not greater than half of the curve order), which complies with the EIP-2 specification and can be used directly in verification scenarios such as OpenZeppelin ECDSA.recover.

When a contract accepts the three parameters (v, r, s) (e.g., ERC-20 Permit's permit(owner, spender, value, deadline, v, r, s)), use the v, r, and s fields; when it accepts bytes signature, use the signature field; when it accepts an EIP-2098 compact signature (r, vs) (e.g., the 1inch Limit Order Protocol), use the r and vs fields.

exchange.IO("hash", "sign", ...) can also sign a 32-byte hash, but it returns the concatenated 65-byte data with v being 0 or 1, consistent with the behavior of previous versions; for on-chain verification scenarios such as EIP-712, it is recommended to use exchange.IO("sign", ...).