|
const { parseEther, Wallet } = require("ethers"); |
|
|
|
// the domain is for the same for all messages; you can hardcode it or derive it |
|
// from this api https://api.testnet.bsx.exchange/chain/configs |
|
const domainData = { |
|
name: "BSX Testnet", |
|
version: "1", |
|
chainId: 84532, |
|
verifyingContract: "0x182C14399BCC7c9F0280Ad07913CB07ba1775Cb6", |
|
}; |
|
|
|
// replace with your account private key |
|
const account = new Wallet( |
|
"0x22f2f8bd71ba7dc47e762cc70b7e5db5ecc45ea4a7babc5268782c58c79c346e" |
|
); |
|
console.log("account", account.address); |
|
//account 0x5A3Ac91883Fd94394F3CFf22dBC93AFB41d5eD3f |
|
|
|
const signer = new Wallet( |
|
"0xdd86166bd13bbfa046967a9b8aa6e2e3c10a8b0bcef902fe63b01ba873148086" |
|
); |
|
console.log("signer", signer.address); |
|
//signer 0x2e086F40822314CFDb72DBeD9C6FCbaEA0Db1c6d |
|
|
|
// this function show example how to build the BE for POST /users/register |
|
const registerSigningKey = async () => { |
|
const signingKeyMessage = { |
|
account: account.address, |
|
}; |
|
const signingKeySignature = await signer.signTypedData( |
|
domainData, |
|
{ |
|
SignKey: [{ name: "account", type: "address" }], |
|
}, |
|
signingKeyMessage |
|
); |
|
console.log("signingKeySignature", signingKeySignature); |
|
//signingKeySignature: 0x5c49b8bcd90c0848696756b132ceb79ecdc3f572ae24cc5bcbd9b299437b24235fcd525dac0545e17e4f65fd51717fa767762a474ca4a82520c6b0b946687b5d1b |
|
|
|
const registerMessage = { |
|
key: signer.address, |
|
message: |
|
"Please sign in with your wallet to access bsx.exchange. You are signing in on Monday, January 17, 2124 9:35:29 AM (GMT). This message is exclusively signed with bsx.exchange for security.", |
|
nonce: "4861157729000000000", |
|
}; |
|
|
|
const accountSignature = await account.signTypedData( |
|
domainData, |
|
{ |
|
Register: [ |
|
{ name: "key", type: "address" }, |
|
{ name: "message", type: "string" }, |
|
{ name: "nonce", type: "uint64" }, |
|
], |
|
}, |
|
registerMessage |
|
); |
|
console.log("accountSignature", accountSignature); |
|
//registerMessage expected: 0xa19f4468cdf8c774ea2a86488a5747aa8ec91c13bd00c839d8725b9eaf594253792c38f54a17176f83312867e78c9d69067be8d922e3f1ddc9efdcfb3cd1d1051b |
|
const body = { |
|
user_wallet: account.address, |
|
signer: signer.address, |
|
nonce: registerMessage.nonce, |
|
wallet_signature: accountSignature, |
|
signer_signature: signingKeySignature, |
|
message: registerMessage.message, |
|
}; |
|
|
|
console.log("SIGNING_BODY:::", body); |
|
// SIGNING_BODY::: { |
|
// user_wallet: '0x5A3Ac91883Fd94394F3CFf22dBC93AFB41d5eD3f', |
|
// signer: '0x2e086F40822314CFDb72DBeD9C6FCbaEA0Db1c6d', |
|
// nonce: '4861157729000000000', |
|
// wallet_signature: '0x22ae531bd56c27930eb16b407b43f2a5e5b8aa57d5b8d13a8c0763dea2ae03037876449da50f1d475c5d9c73ce71fb591857d17647171fa87033a189bd2db85a1c', |
|
// signer_signature: '0x833896aee9c6b0a6c4985fb983a9659c7eb4f23d0824aaddc3d23bb6148ac90c6d705f928da1b6a1e61523325cecfcd82ff647c3c45f6054f61ac7f6326e9a3f1b', |
|
// message: 'Please sign in with your wallet to access bsx.exchange. You are signing in on Monday, January 17, 2124 9:35:29 AM (GMT). This message is exclusively signed with bsx.exchange for security.' |
|
// } |
|
}; |
|
|
|
// this functions show example how to build the BE for POST /orders |
|
const onCreateOrder = async (payload) => { |
|
const { |
|
side, |
|
product_index, |
|
type = "LIMIT", |
|
price, |
|
size, |
|
time_in_force = type === "MARKET" ? "FOK" : "GTC", |
|
nonce, |
|
} = payload; |
|
|
|
// to sign the order we need to build the message |
|
// 1 thing should be noted here is that the order message is a little bit different from the other messages |
|
// the price, size in body is float, we must convert it to uint128 (by using parseEther - it simply multiply the float by 10^18, so we have an integer) |
|
const orderMessage = { |
|
sender: account.address, |
|
size: parseEther(size).toString(), // this field is different in the request body |
|
price: parseEther(price).toString(), // this field is different in the request body |
|
nonce: nonce, |
|
productIndex: product_index, |
|
orderSide: side === "BUY" ? 0 : 1, |
|
}; |
|
|
|
const orderSignature = await signer.signTypedData( |
|
domainData, |
|
{ |
|
Order: [ |
|
{ name: "sender", type: "address" }, |
|
{ name: "size", type: "uint128" }, |
|
{ name: "price", type: "uint128" }, |
|
{ name: "nonce", type: "uint64" }, |
|
{ name: "productIndex", type: "uint8" }, |
|
{ name: "orderSide", type: "uint8" }, |
|
], |
|
}, |
|
orderMessage |
|
); |
|
console.log("orderSignature", orderSignature); |
|
//orderSignature expected: 0xafd6693decaeb17d005b788171ca942b74cd407f12dcccb0e87f1201e48ba9050bec18054301a00e6769e9e6cf50d24b3c287fb7fed59b2b41129b91edeffc4c1b |
|
|
|
const body = { |
|
side: side, |
|
product_index: product_index, |
|
price: price, |
|
size: size, |
|
time_in_force: time_in_force, |
|
nonce: nonce, |
|
signature: orderSignature, |
|
}; |
|
console.log("ORDER_BODY:::", body); |
|
// ORDER_BODY::: { |
|
// side: 'BUY', |
|
// product_index: 1, |
|
// price: '2500', |
|
// size: '2', |
|
// time_in_force: 'GTC', |
|
// nonce: '1234123412341234', |
|
// signature: '0x2aa5b3fa914a5aae71cc0d7799f3ec469add02f1459e5c588fa2c9e05a5e6b5a7ab59f790d76b873d7904bc43e0e24dcccca671c4053c775d1e6395cb99e264a1b' |
|
// } |
|
}; |
|
|
|
const onCreateWithdraw = async (payload) => { |
|
const withdrawMessage = { |
|
sender: account.address, |
|
token: payload.token, |
|
amount: parseEther(payload.amount), // payload.amount is float, we must convert it to uint128 (by using parseEther) |
|
nonce: payload.nonce, |
|
}; |
|
|
|
const withdrawSignature = await signer.signTypedData( |
|
domainData, |
|
{ |
|
Withdraw: [ |
|
{ name: "sender", type: "address" }, |
|
{ name: "token", type: "address" }, |
|
{ name: "amount", type: "uint128" }, |
|
{ name: "nonce", type: "uint64" }, |
|
], |
|
}, |
|
withdrawMessage |
|
); |
|
console.log("withdrawSignature", withdrawSignature); |
|
//withdrawSignature expected: 0x01479ab04e421ecb07ad18556a7edf1a90e85ead460056aca28bf30d22a1af074ba633567ee2b2f3ed4effae21e78ad7217b53595138c456b3959ff4139507731b |
|
const body = { |
|
sender: account.address, |
|
token: payload.token, |
|
amount: payload.amount, |
|
nonce: payload.nonce, |
|
wallet_signature: withdrawSignature, |
|
}; |
|
console.log("WITHDRAW_BODY:::", body); |
|
// WITHDRAW_BODY::: { |
|
// sender: '0x5A3Ac91883Fd94394F3CFf22dBC93AFB41d5eD3f', |
|
// token: '0x26dF8d79C4FaCa88d0212f0bd7C4A4d1e8955F0e', |
|
// amount: '1.2', |
|
// nonce: '1230004310000', |
|
// wallet_signature: '0x557e80b720b7f3a14494182ab1ae096ab9fd32e8b85444022a132ff0fe4f580f373fc785370b681065d4fed95059ce10a3e67e5bdeae4d33c016624c0d897b541b' |
|
// } |
|
}; |
|
|
|
(async () => { |
|
await registerSigningKey(); |
|
await onCreateOrder({ |
|
side: "BUY", |
|
product_index: 1, |
|
price: "2500", |
|
size: "2", |
|
signing_time: "1690434000000000000", |
|
nonce: "1234123412341234", |
|
}); |
|
await onCreateWithdraw({ |
|
token: "0x26dF8d79C4FaCa88d0212f0bd7C4A4d1e8955F0e", |
|
amount: "1.2", |
|
nonce: "1230004310000", |
|
}); |
|
})(); |