Нэг блокчэйнээс өөр нэг блокчэйнд токэнийг шууд зөөх боломжгүй гэж хэлж болно. Учир нь өөр өөр блокчэйн өөр өөрийн гэсэн дүрэм, төлбөрийн хэрэгсэлтэй байдаг. Гэтэл крипто хөрөнгийг блокчэйн хооронд зөөх нь DeFi-д зайлшгүй байх ёстой чухал хэрэгцээ юм. Үүнийг ухаалаг гэрээ, боодолтой токэний тусламжтайгаар холбогч гүүрийг ашиглан шийддэг.
Энэхүү заавраар бүгдээрээ Ethereum блокчэйн сүлжээн дахь ETH-ийг Корэкс сүлжээн дээр CRX болгох гүүрийг байгуулах жишээг харах болно.
Хоёр блокчэйн хооронд крипто хөрөнгө дамжуулахдаа блокчэйн бүр дээр тус тусыг ухаалаг гэрээг үүсгэнэ. Ухаалаг гэрээнд хийгдсэн үйлдлүүд дээр event үүсгэгдэх ба энэ нь блокчэйнд хадгалагдан үлддэг. Бидний хэрэгжүүлэх гүүр, хоёр блокчэйнээс event сонсох ба сонссон event-ийн дагуу үйлдлийг хийнэ.
Ethereum сүлжээн дээрх ухаалаг гэрээ эхлээд ETH-ийн дүүргэлттэй байх ёстой. Мөн түүнчлэн TEO сүлжээн дээрх ухаалаг гэрээ CRX-ийн дүүргэлттэй байх ёстой.
Зурагт харуулсны дагуу Ethereum сүлжээн дээр ETH2CRX гэрээ байрлана. Уг гэрээ нь дотроо ETH хадгалах бөгөөд корэкс дээр гүйлгээ хийх үнэ cost, болон CRX/ETH ханш crxeth-ийг хадгална.
CRX2ETH гэрээ нь CRX-ийг ETH болгох мөн Ethereum сүлжээнээс орж ирсэн захиалгын CRX-ийг түгээх үйлдлүүдийг хариуцна. Уг гэрээ нь дотроо гэрээний эзэн owner, CRX-ийг ETH болгох ханш ethcrx, Ethereum сүлжээн дээр хийгдэх гүйлгээний хураамж cost зэргийг агуулна.
Ухаалаг гэрээний event-үүд блокчэйнд хадгалагдан үлддэг тул хэзээч гэсэн тэр event-ийг ухаж үзэх боломжтой гэсэн үг юм. Ухаалаг гэрээний үүсгэсэн event-ийг web3js ашиглан хоёр янзаар сонсох боломжтой.
Гэрээний event функцийг ашиглан гэрээнээс гарсан өөрчлөлтүүдийг чагнах боломжтой. Доор жишээнд ToCorex
event-ийг сонсох ба data
дээр шинээр үүсгэгдсэн event-ийн мэдээлэл ирдэг. Уг арга ажиллахын тулд ABI зөв байх ёстойг анхаарна уу.
const addr = '<address of the contract>'
abi = JSON.parse('<contract abi>');
ETH2CRX = new this.web3.eth.Contract(abi, addr);
let options = {
filter: {
value: [],
},
fromBlock: 0
};
ETH2CRX.events.ToCorex(options)
.on('data', event => eth2crx_process(event))
.on('changed', changed => console.log(changed))
.on('error', err => throw err)
.on('connected', str => console.log(str))
const crx_owner_addr = '<address of the owner of CRX2ETH contract>'
const crx_owner_privateKey = '<private key of the owner>'
function eth2crx_process(e) {
if (e.event == 'ToCorex') {
let dst = e.returnValues.dst;
let val = e.returnValues.val;
transfer({
from: crx_owner_addr,
to: crx2eth_addr,
value: '0',
data: CRX2ETH.methods.toCorex(dst, val).encodeABI(),
privateKey: crx_owner_privateKey,
}).then(tx => {console.log('Tx successful: ', tx.transactionHash)});
} else {
try {
console.log(e.event, ' occurred: ', e.returnValues)
} catch (e) {
console.log('Error occured: ', e)
}
}
}
async transfer({ from, to, value, data, privateKey }) {
const chainId = await this.web3.eth.getChainId()
const gasPrice = await this.web3.eth.getGasPrice();
const privateKeyBuffer = EthUtil.toBuffer(privateKey);
const nonce = await this.web3.eth.getTransactionCount(from, 'pending');
const rawTx = {
from,
to,
chainId: Web3.utils.toHex(chainId),
value: Web3.utils.toHex(value),
gasLimit: Web3.utils.toHex(50000),
gasPrice: Web3.utils.toHex(gasPrice),
data: data,
nonce: Web3.utils.toHex(nonce),
};
const tx = new Tx(rawTx);
tx.sign(privateKeyBuffer);
const serializedTx = tx.serialize();
const res = await this.web3.eth.sendSignedTransaction(`0x${serializedTx.toString('hex')}`);
return res;
}
Бидний жишээнд харуулсан гүүрийг доорх client.js, main.js файлуудад харуулав.
const EthUtil = require('ethereumjs-util');
const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
class Client {
constructor(connection) {
this.web3 = new Web3(connection);
}
async transfer({ from, to, value, data, privateKey }) {
const chainId = await this.web3.eth.getChainId()
const gasPrice = await this.web3.eth.getGasPrice();
const privateKeyBuffer = EthUtil.toBuffer(privateKey);
const nonce = await this.web3.eth.getTransactionCount(from, 'pending');
const rawTx = {
from,
to,
chainId: Web3.utils.toHex(chainId),
value: Web3.utils.toHex(value),
gasLimit: Web3.utils.toHex(50000),
gasPrice: Web3.utils.toHex(gasPrice),
data: data,
nonce: Web3.utils.toHex(nonce),
};
const tx = new Tx(rawTx);
tx.sign(privateKeyBuffer);
const serializedTx = tx.serialize();
const res = await this.web3.eth.sendSignedTransaction(`0x${serializedTx.toString('hex')}`);
return res;
}
get_contract(abi, addr) {
var contract = new this.web3.eth.Contract(abi, addr);
return contract;
}
async get_balance(addr) {
const bal = await this.web3.eth.getBalance(addr);
return bal;
}
};
module.exports = Client;
const Web3 = require('web3');
const net = require('net')
const Client = require('./client');
const crx2eth_addr = '0x.....';
const crx2eth_abi_json = '[{"constant": true,"inputs": [],"name": "cost","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "dst","type": "address"}],"name": "toEthereum","outputs": [],"payable": true,"stateMutability": "payable","type": "function"},{"constant": true,"inputs": [],"name": "owner","outputs": [{"name": "","type": "address"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "ethcrx","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "dst","type": "address"},{"name": "val","type": "uint256"}],"name": "toCorex","outputs": [],"payable": true,"stateMutability": "payable","type": "function"},{"inputs": [],"payable": false,"stateMutability": "nonpayable","type": "constructor"},{"payable": true,"stateMutability": "payable","type": "fallback"},{"anonymous": false,"inputs": [{"indexed": true,"name": "dst","type": "address"},{"indexed": false,"name": "val","type": "uint256"}],"name": "ToCorex","type": "event"},{"anonymous": false,"inputs": [{"indexed": true,"name": "dst","type": "address"},{"indexed": false,"name": "val","type": "uint256"}],"name": "ToEthereum","type": "event"}]';
const crx2eth_abi = JSON.parse(crx2eth_abi_json)
const crx_owner_addr = '0x.....'
const crx_owner_privateKey = '0x.....';
const eth2crx_addr = '0x.....';
const eth2crx_abi_json = '[{"constant":true,"inputs":[],"name":"cost","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"crxeth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"toCorex","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"val","type":"uint256"}],"name":"toEthereum","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"val","type":"uint256"}],"name":"ToCorex","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"val","type":"uint256"}],"name":"ToEthereum","type":"event"}]';
const eth2crx_abi = JSON.parse(eth2crx_abi_json)
const eth_owner_addr = '0x.....';
const eth_owner_privateKey = '0x.....';
var corex_web3 = new Web3.providers.IpcProvider('/home/corex/.corexchain/corex.ipc', net)
var eth_web3 = new Web3.providers.WebsocketProvider('ws://localhost:8545');
var corex_cli = new Client(corex_web3);
var eth_cli = new Client(eth_web3);
var crx2eth_contract = corex_cli.get_contract(crx2eth_abi, crx2eth_addr);
var eth2crx_contract = eth_cli.get_contract(eth2crx_abi, eth2crx_addr);
let options = {
filter: {
value: [],
},
fromBlock: 0
};
function crx2eth_process(e) {
if (e.event == 'ToEthereum') {
let dst = e.returnValues.dst;
let val = e.returnValues.val;
eth_cli.transfer({
from: eth_owner_addr,
to: eth2crx_addr,
value: '0',
data: eth2crx_contract.methods.toEthereum(dst, val).encodeABI(),
privateKey: eth_owner_privateKey,
}).then(tx => { console.log('Tx successful: ', tx.transactionHash) });
} else {
try {
console.log(e.event, ' occurred: ', e.returnValues)
} catch (e) {
console.log('Error occured: ', e)
}
}
}
function eth2crx_process(e) {
if (e.event == 'ToCorex') {
let dst = e.returnValues.dst;
let val = e.returnValues.val;
eth_cli.transfer({
from: crx_owner_addr,
to: crx2eth_addr,
value: '0',
data: crx2eth_contract.methods.toCorex(dst, val).encodeABI(),
privateKey: crx_owner_privateKey,
}).then(tx => {console.log('Tx successful: ', tx.transactionHash)});
} else {
try {
console.log(e.event, ' occurred: ', e.returnValues)
} catch (e) {
console.log('Error occured: ', e)
}
}
}
try {
crx2eth_contract.events.ToEthereum(options)
.on('data', event => crx2eth_process(event))
.on('changed', changed => console.log(changed))
.on('error', err => { throw err;})
.on('connected', str => console.log(str));
} catch (e) {
console.log(e)
}
try {
crx2eth_contract.events.ToCorex(options)
.on('data', event => console.log(event))
.on('changed', changed => console.log(changed))
.on('error', err => { throw err;})
.on('connected', str => console.log(str))
} catch (e) {
console.log(e);
}
try {
eth2crx_contract.events.ToEthereum(options)
.on('data', event => console.log(event))
.on('changed', changed => console.log(changed))
.on('error', err => { throw err;})
.on('connected', str => console.log(str))
} catch (e) {
console.log(e);
}
try {
eth2crx_contract.events.ToCorex(options)
.on('data', event => crx2eth_process(event))
.on('changed', changed => console.log(changed))
.on('error', err => { throw err;})
.on('connected', str => console.log(str))
} catch (e) {
console.log(e);
}
console.log('Listening for events');