1. 交易所接入
1.1 节点搭建
交易所节点搭建步骤和基本操作命令请参考 《开发者指南 3.4 节点搭建》、《开发者指南 3.5 基本命令》。在测试网测试无误后,联系我们(邮箱地址:developer@sdchain.io)获取正式网的配置文件,并告知服务商节点IP。配置方式如下:
如果是在当前服务器上切换到正式网,需要先清除测试网的账本:
cd /usr/local/sdchaind
./sdchaind stop
rm –rf ./db
再配置正式网配置文件:
mv official/SDChain-Core.cfg /usr/local/sdchaind/
mv official/validators.txt /usr/local/sdchaind/
完成配置后启动运行,并验证是否启动成功。
1.2 代码示例
const exchangeAccount = "6BCNL443M1Qhw6i42b2yyFFpHPgEkACiuo";
const exchangePrivateKey = "";
const safeBlockNum = 30;
const baseDrops = 1000000;
监听充币
// Listening for deposits
async function deposits() {
while (true) {
try {
// Get last validated block
const lastBlockNum = await getLastBlockNum();
// Get last block from exchange db
const syncedBlockNum = await getSyncedBlockNum();
const minBlockNum = syncedBlockNum + 1;
const maxBlockNum = lastBlockNum - safeBlockNum;
// Block not increase
if (maxBlockNum < minBlockNum) {
tools.sleep(20000);
continue;
}
// Get all payment transactions by block
const payments = await getPayments(minBlockNum, maxBlockNum);
for (i = 0; i < payments.length; i++) {
const tx = payments[i];
const hash = tx.hash;
const fromAccount = tx.Account;
const toAccount = tx.Destination;
// 1SDA=1000000Drops
const amount = dropsToBase(tx.Amount);
// Hex2String
const memo = parseMemo(tx.Memos);
// Valid payments
await checkAndSaveToDB(hash, fromAccount, toAccount, amount, memo);
}
updateSyncedBlockNum(maxBlockNum);
} catch (e) {
// Log something
console.log(e);
await tools.sleep(10000);
}
}
}
//Get last validated block
async function getLastBlockNum() {
let response = null;
try {
response = await request({
uri: rpcUrl,
method: "POST",
body: {
"method": "ledger",
"params": [
{
"ledger_index": "validated",
"accounts": false,
"full": false,
"transactions": false,
"expand": false,
"owner_funds": false
}
]
},
json: true
});
} catch (e) {
// Log something
console.log(e);
return null;
}
// Submit success
if (response && response.result && response.result.status == "success") {
return response.result.ledger_index;
} else {
// log something
console.log(response.result);
return null;
}
}
// Get all payment transactions by block
async function getPayments(minBlockNum, maxBlockNum) {
const payments = [];
try {
let marker = null;
while (true) {
const response = await request({
uri: rpcUrl,
method: "POST",
body: {
"method": "account_tx",
"params": [
{
"account": exchangeAccount,
"binary": false,
"forward": false,
"ledger_index_min": minBlockNum,
"ledger_index_max": maxBlockNum,
"marker": marker,
"limit": 1000
}
]
},
json: true
});
result = response.result;
marker = result.marker;
for (i = 0; i < result.transactions.length; i++) {
const txInfo = result.transactions[i];
// Failed transaction
if (txInfo.meta.TransactionResult != "tesSUCCESS") {
continue;
}
// Not payment
if (txInfo.tx.TransactionType != "Payment") {
continue;
}
payments.push(txInfo.tx);
}
// No more transactions
if (!marker) {
break;
}
}
return payments;
} catch (e) {
// Log something
console.log(e);
return null;
}
}
// Hex memo to string
function parseMemo(memos) {
if (memos.length == 0) {
return null;
}
const hexMemo = memos[0].Memo.MemoData;
const memo = new Buffer(hexMemo, "hex").toString("utf-8");
return memo;
}
function dropsToBase(amount) {
return (new BigNumber(amount)).dividedBy(baseDrops).toString()
}
提币和提币校验
// User withdraw
async function withdraw(toAccount, amount, memo) {
const requestParams = {
"offline": false,
"secret": exchangePrivateKey,
"tx_json": {
"Account": exchangeAccount,
"Amount": baseToDrops(amount),
"Destination": toAccount,
"TransactionType": "Payment"
}
};
if (memo) {
// Memo must be hex
const hexType = new Buffer("type").toString("hex");
const hexMemo = new Buffer(memo).toString("hex");
requestParams.tx_json.Memos = [];
requestParams.tx_json.Memos.push({
"Memo": {
"MemoType": hexType,
"MemoData": hexMemo
}
});
}
const response = await request({
uri: rpcUrl,
method: "POST",
body: {
"method": "submit",
"params": [
requestParams
]
},
json: true
});
const result = response.result;
if (result.status == "success" && result.engine_result == "tesSUCCESS") {
// Submit success wait validate
return result.tx_json.hash;
} else {
// Submit error
// Log something
console.log(JSON.stringify(result));
}
return null;
}
// Check withdraw status
async function withdrawCheck(hash) {
const response = await request({
uri: rpcUrl,
method: "POST",
body: {
"method": "tx",
"params": [
{
"transaction": hash,
"binary": false
}
]
},
json: true
});
const result = response.result;
if (result.status == "success") {
if (result.validated && result.meta) {
if (result.meta.TransactionResult == "tesSUCCESS") {
// Success
return 1;
} else {
// Faild transaction
return -1;
}
} else {
// Not completed
return 0;
}
} else {
// Faild transaction
return -1;
}
}
function baseToDrops(amount) {
return (new BigNumber(amount)).multipliedBy(baseDrops).toString()
}