Skip to content

Commit

Permalink
fix(tron): add trc10 test for ci (#33)
Browse files Browse the repository at this point in the history
* fix(tron): add trc10 test for ci

* fix(tron): add check balance

* fix(tron): rm unused code
  • Loading branch information
JacobDenver007 committed Apr 12, 2021
1 parent ca42aff commit dd35100
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 46 deletions.
2 changes: 1 addition & 1 deletion offchain-modules/config.json.example
Expand Up @@ -95,7 +95,7 @@
"EE782FE170F680D6CAB340ECA5ED2F6E05B0B9809082CF745207E87734211C72"
]
},
"feeLimit": 1000000
"feeLimit": 10000000
}
}
}
3 changes: 2 additions & 1 deletion offchain-modules/src/packages/handlers/ckb.ts
Expand Up @@ -14,6 +14,7 @@ import Transaction = CKBComponents.Transaction;
import { Script as LumosScript } from '@ckb-lumos/base';
import { BigNumber } from 'ethers';
import { RecipientCellData } from '@force-bridge/ckb/tx-helper/generated/eth_recipient_cell';
import { getAssetTypeByAsset } from '@force-bridge/xchain/tron/utils';

// CKB handler
// 1. Listen CKB chain to get new burn events.
Expand Down Expand Up @@ -55,7 +56,7 @@ export class CkbHandler {
{
ckbTxHash: burn.ckbTxHash,
asset: burn.asset,
assetType: burn.asset,
assetType: getAssetTypeByAsset(burn.asset),
amount: burn.amount,
recipientAddress: burn.recipientAddress,
},
Expand Down
23 changes: 8 additions & 15 deletions offchain-modules/src/packages/handlers/tron.ts
Expand Up @@ -6,6 +6,7 @@ import { ITronLock, TronUnlock, ICkbMint, TronLock } from '@force-bridge/db/mode
import { ChainType } from '@force-bridge/ckb/model/asset';
import { promises } from 'fs';
import { sign } from '@force-bridge/ckb/tx-helper/signer';
import { getAssetTypeByAsset } from '@force-bridge/xchain/tron/utils';
const TronWeb = require('tronweb');
const TronGrid = require('trongrid');

Expand Down Expand Up @@ -77,6 +78,10 @@ export class TronHandler {
fingerprint: fingerprint,
});
for (const data of txs.data) {
if (Object.keys(data.token_info).length == 0) {
logger.debug('invalid trc20 tx, token info is undefined', data);
continue;
}
const tx = await this.tronWeb.trx.getTransaction(data.transaction_id);
const event = {
tx_hash: data.transaction_id,
Expand All @@ -103,17 +108,6 @@ export class TronHandler {
return { ckbRecipient, sudtExtraData };
}

private getAssetTypeByAsset(asset: string) {
switch (asset.length) {
case TRX_ASSET_LENGTH:
return 'trx';
case TRC10_ASSET_LENGTH:
return 'trc10';
default:
return 'trc20';
}
}

private transferEventToCkbMint(event: TronLockEvent) {
const { ckbRecipient, sudtExtraData } = this.analyzeMemo(event.memo);
return {
Expand All @@ -132,7 +126,7 @@ export class TronHandler {
txIndex: 0,
sender: event.sender,
asset: event.asset,
assetType: this.getAssetTypeByAsset(event.asset),
assetType: getAssetTypeByAsset(event.asset),
amount: event.amount,
memo: event.memo,
timestamp: event.timestamp,
Expand Down Expand Up @@ -162,7 +156,7 @@ export class TronHandler {
const trc20LockEvents = await this.getTrc20TxsLockEvents(minTimestamp);

const totalLockEvents = trxAndTrc10Events.concat(trc20LockEvents);
logger.debug('total lock events', totalLockEvents.length);
logger.debug('total lock events', totalLockEvents);

for (const event of totalLockEvents) {
if (event.timestamp <= minTimestamp) {
Expand Down Expand Up @@ -227,7 +221,6 @@ export class TronHandler {
for (const key of this.committee.keys) {
signed_tx = await this.tronWeb.trx.multiSign(signed_tx, key);
}

return signed_tx;
}

Expand Down Expand Up @@ -276,7 +269,6 @@ export class TronHandler {
logger.debug('flush pending tx to confirm');
const pendingRecords = await this.db.getTronUnlockRecords('pending');
for (const pendingRecord of pendingRecords) {
// todo: check tx is confirmed
try {
const confirmedTx = await this.tronWeb.trx.getConfirmedTransaction(pendingRecord.tronTxHash);
console.log(confirmedTx);
Expand Down Expand Up @@ -306,6 +298,7 @@ export class TronHandler {
signedTx = await this.multiSignTransferTrc20(unlockRecord);
break;
}

unlockRecord.tronTxHash = signedTx.txID;
unlockRecord.tronTxIndex = 0;
unlockRecord.status = 'pending';
Expand Down
13 changes: 13 additions & 0 deletions offchain-modules/src/packages/xchain/tron/utils.ts
@@ -0,0 +1,13 @@
const TRX_ASSET_LENGTH = 3;
const TRC10_ASSET_LENGTH = 7;

export function getAssetTypeByAsset(asset: string): string {
switch (asset.length) {
case TRX_ASSET_LENGTH:
return 'trx';
case TRC10_ASSET_LENGTH:
return 'trc10';
default:
return 'trc20';
}
}
131 changes: 102 additions & 29 deletions offchain-modules/src/scripts/integration-test/tron.ts
Expand Up @@ -37,6 +37,36 @@ async function transferTrx(tronWeb, from, to, amount, memo, priv) {
return broad_tx;
}

async function transferTrc10(tronWeb, from, to, amount, tokenID, memo, priv) {
const unsigned_tx = await tronWeb.transactionBuilder.sendToken(to, amount, tokenID, from);
const unsignedWithMemoTx = await tronWeb.transactionBuilder.addUpdateData(unsigned_tx, memo, 'utf8');
const signed_tx = await tronWeb.trx.sign(unsignedWithMemoTx, priv);
const broad_tx = await tronWeb.trx.broadcast(signed_tx);
return broad_tx;
}

async function transferTrc20(tronWeb, from, to, amount, contractAddress, memo, priv) {
const options = {};
const functionSelector = 'transfer(address,uint256)';
const params = [
{ type: 'address', value: to },
{ type: 'uint256', value: amount },
];

const unsigned_tx = await tronWeb.transactionBuilder.triggerSmartContract(
contractAddress,
functionSelector,
options,
params,
from,
);
const unsignedWithMemoTx = await tronWeb.transactionBuilder.addUpdateData(unsigned_tx.transaction, memo, 'utf8');

const signed_tx = await tronWeb.trx.sign(unsignedWithMemoTx, priv);
const broad_tx = await tronWeb.trx.broadcast(signed_tx);
return broad_tx;
}

async function main() {
const conn = await createConnection();

Expand All @@ -59,14 +89,51 @@ async function main() {
const recipientLockscript = 'ckt1qyqyph8v9mclls35p6snlaxajeca97tc062sa5gahk';
const sudtExtraData = 'transfer 100 to ckt1qyqyph8v9mclls35p6snlaxajeca97tc062sa5gahk';
const memo = recipientLockscript.concat(',').concat(sudtExtraData);
const lockRes = await transferTrx(tronWeb, from, to, amount, memo, userPrivateKey);
const txHash: string = lockRes.transaction.txID;

const trxLockRes = await transferTrx(tronWeb, from, to, amount, memo, userPrivateKey);
const trxTxHash: string = trxLockRes.transaction.txID;

const trc10LockRes = await transferTrc10(tronWeb, from, to, amount, '1000696', memo, userPrivateKey);
const trc10TxHash: string = trc10LockRes.transaction.txID;

const trc20LockRes = await transferTrc20(
tronWeb,
from,
to,
amount,
'TVWvkCasxAJUyzPKMQ2Rus1NtmBwrkVyBR',
memo,
userPrivateKey,
);
const trc20TxHash: string = trc20LockRes.transaction.txID;

// create tron unlock
const recipientAddress = 'TS6VejPL8cQy6pA8eDGyusmmhCrXHRdJK6';
let sendBurn = false;
let burnTxHash;
const checkEffect = async () => {

const getBalance = async (assetName) => {
const account = new Account(PRI_KEY);
const ownLockHash = ckb.utils.scriptToHash(<CKBComponents.Script>await account.getLockscript());
const asset = new TronAsset(assetName, ownLockHash);
const bridgeCellLockscript = {
codeHash: ForceBridgeCore.config.ckb.deps.bridgeLock.script.codeHash,
hashType: ForceBridgeCore.config.ckb.deps.bridgeLock.script.hashType,
args: asset.toBridgeLockscriptArgs(),
};
const sudtArgs = ckb.utils.scriptToHash(<CKBComponents.Script>bridgeCellLockscript);
const sudtType = {
codeHash: ForceBridgeCore.config.ckb.deps.sudtType.script.codeHash,
hashType: ForceBridgeCore.config.ckb.deps.sudtType.script.hashType,
args: sudtArgs,
};
const balance = await collector.getSUDTBalance(
new Script(sudtType.codeHash, sudtType.args, sudtType.hashType),
await account.getLockscript(),
);
return balance;
};

const checkLock = async (txHash, assetName, assetType, sendBurn) => {
// check TronLock and CkbMint saved.
const tronLockRecords = await conn.manager.find(TronLock, {
where: {
Expand All @@ -79,8 +146,8 @@ async function main() {

assert(tronLockRecord.memo === memo);
assert(tronLockRecord.sender === from);
assert(tronLockRecord.asset === 'trx');
assert(tronLockRecord.assetType === 'trx');
assert(tronLockRecord.asset === assetName);
assert(tronLockRecord.assetType === assetType);

const ckbMintRecords = await conn.manager.find(CkbMint, {
where: {
Expand All @@ -93,54 +160,45 @@ async function main() {
assert(ckbMintRecord.chain === ChainType.TRON);
assert(ckbMintRecord.sudtExtraData === sudtExtraData);
assert(ckbMintRecord.status === 'success');
// assert(ckbMintRecord.asset === 'trx');
assert(ckbMintRecord.asset === assetName);
assert(ckbMintRecord.amount === amount.toString());
assert(ckbMintRecord.recipientLockscript === recipientLockscript);

// check sudt balance.
const account = new Account(PRI_KEY);
const ownLockHash = ckb.utils.scriptToHash(<CKBComponents.Script>await account.getLockscript());
const asset = new TronAsset('trx', ownLockHash);
const bridgeCellLockscript = {
codeHash: ForceBridgeCore.config.ckb.deps.bridgeLock.script.codeHash,
hashType: ForceBridgeCore.config.ckb.deps.bridgeLock.script.hashType,
args: asset.toBridgeLockscriptArgs(),
};
const sudtArgs = ckb.utils.scriptToHash(<CKBComponents.Script>bridgeCellLockscript);
const sudtType = {
codeHash: ForceBridgeCore.config.ckb.deps.sudtType.script.codeHash,
hashType: ForceBridgeCore.config.ckb.deps.sudtType.script.hashType,
args: sudtArgs,
};
const balance = await collector.getSUDTBalance(
new Script(sudtType.codeHash, sudtType.args, sudtType.hashType),
await account.getLockscript(),
);
const balance = await getBalance(assetName);

if (!sendBurn) {
logger.debug('assetName', assetName);
logger.debug('sudt balance:', balance);
logger.debug('expect balance:', new Amount(amount.toString()));
assert(balance.eq(new Amount(amount.toString())));
}
};

const burn = async (sendBurn, assetName, txHash) => {
const burnAmount = 1;
// send burn tx
if (!sendBurn) {
const account = new Account(PRI_KEY);
const ownLockHash = ckb.utils.scriptToHash(<CKBComponents.Script>await account.getLockscript());
const generator = new CkbTxGenerator(ckb, new IndexerCollector(indexer));
const burnTx = await generator.burn(
await account.getLockscript(),
recipientAddress,
new TronAsset('trx', ownLockHash),
new TronAsset(assetName, ownLockHash),
new Amount(burnAmount.toString()),
);
const signedTx = ckb.signTransaction(PRI_KEY)(burnTx);
burnTxHash = await ckb.rpc.sendTransaction(signedTx);
console.log(`burn Transaction has been sent with tx hash ${burnTxHash}`);
await waitUntilCommitted(ckb, burnTxHash, 60);
sendBurn = true;
return burnTxHash;
}
return txHash;
};

const checkUnlock = async (burnTxHash, assetName) => {
const burnAmount = 1;
const balance = await getBalance(assetName);

logger.debug('sudt balance:', balance);
const expectBalance = new Amount((amount - burnAmount).toString());
Expand All @@ -159,10 +217,25 @@ async function main() {
};

// try 100 times and wait for 3 seconds every time.
let trxSendBurn = false;
let trc10SendBurn = false;
let burnTrxTxHash = '';
let burnTrc10TxHash = '';

for (let i = 0; i < 100; i++) {
await asyncSleep(10000);
try {
await checkEffect();
await checkLock(trxTxHash, 'trx', 'trx', trxSendBurn);
burnTrxTxHash = await burn(trxSendBurn, 'trx', burnTrxTxHash);
trxSendBurn = true;
await checkUnlock(burnTrxTxHash, 'trx');

await checkLock(trc10TxHash, '1000696', 'trc10', trc10SendBurn);
burnTrc10TxHash = await burn(trc10SendBurn, '1000696', burnTrc10TxHash);
trc10SendBurn = true;
await checkUnlock(burnTrc10TxHash, '1000696');

//await checkEffect(trc20TxHash, 'TVWvkCasxAJUyzPKMQ2Rus1NtmBwrkVyBR', 'trc20');
} catch (e) {
logger.warn('The tron component integration not pass yet.', { i, e });
continue;
Expand Down

0 comments on commit dd35100

Please sign in to comment.