# Блокчэйн хоорондын гүүр

Нэг блокчэйнээс өөр нэг блокчэйнд токэнийг шууд зөөх боломжгүй гэж хэлж болно. Учир нь өөр өөр блокчэйн өөр өөрийн гэсэн дүрэм, төлбөрийн хэрэгсэлтэй байдаг. Гэтэл крипто хөрөнгийг блокчэйн хооронд зөөх нь **DeFi**-д зайлшгүй байх ёстой чухал хэрэгцээ юм. Үүнийг ухаалаг гэрээ, боодолтой токэний тусламжтайгаар холбогч гүүрийг ашиглан шийддэг.

Энэхүү заавраар бүгдээрээ Ethereum блокчэйн сүлжээн дахь ETH-ийг Корэкс сүлжээн дээр CRX болгох гүүрийг байгуулах жишээг харах болно.

{% hint style="warning" %}
Энд бичигдсэн код нь зөвхөн үзүүлэнд зориулж бичигдсэн тул үйлчилгээнд хэрэглэхэд тохиромжгүй гэдгийг анхаарна уу!
{% endhint %}

## Хэрэгжүүлэлт

Хоёр блокчэйн хооронд крипто хөрөнгө дамжуулахдаа блокчэйн бүр дээр тус тусыг ухаалаг гэрээг үүсгэнэ. Ухаалаг гэрээнд хийгдсэн үйлдлүүд дээр **event** үүсгэгдэх ба энэ нь блокчэйнд хадгалагдан үлддэг. Бидний хэрэгжүүлэх **гүүр**, хоёр блокчэйнээс event сонсох ба сонссон event-ийн дагуу үйлдлийг хийнэ.<br>

![Ethereum, Corexchain хооронд ETH, CRX дамжуулах гүүрний архитектур](https://3584451794-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fk8ArHG3L17wkbmKRlvP6%2Fuploads%2FL8Yq48GHNJquEZtZUNeT%2Fbridge.png?alt=media\&token=5d07904e-1305-43c5-82bd-dc7a7b49081d)

Ethereum сүлжээн дээрх ухаалаг гэрээ эхлээд ETH-ийн дүүргэлттэй байх ёстой. Мөн түүнчлэн TEO сүлжээн дээрх ухаалаг гэрээ CRX-ийн дүүргэлттэй байх ёстой.

### Ethereum сүлжээн дээрх ухаалаг гэрээ

Зурагт харуулсны дагуу Ethereum сүлжээн дээр ETH2CRX гэрээ байрлана. Уг гэрээ нь дотроо ETH хадгалах бөгөөд корэкс дээр гүйлгээ хийх үнэ *cost*, болон CRX/ETH ханш crxeth-ийг хадгална.  &#x20;

* ***toCorex*** үйлдлийг корэкс-ийн ямар хаягт шилжүүлэх хаягийг дамжуулан, ETH шилжүүлж гүйлгээ хийхэд *ToCorex* event ялгарах болно. Шилжүүлсэн ETH-ээс гүйлгээний хураамжыг авч, ханшаар хөрвүүлж event үүсгэн блокчэйнд хадгална. Энэ event-ийг гүүр сонсох юм.
* **toEthereum** үйлдлийг зөвхөн *owner* дуудах бөгөөд корэкс сүлжээнээс ETH-ийг захиалсны дараагаар гүүрээр дамжин Ethereum сүлжээнд, захиалсан ETH-ийг түгээхэд ашиглана.&#x20;

```solidity
contract ETH2CRX {

    uint public cost;                // corex chain дээр гүйлгээ хийх үнэ
    uint public crxeth;
    address public owner;
    
    event ToCorex(address indexed dst, uint val);
    event ToEthereum(address indexed dst, uint val);

    constructor() public {
        owner = msg.sender;
        cost = 0.01 ether;
        crxeth = 607715;
    }

    function() external payable {
    }
    
    function toCorex(address to) external payable {
	    require(msg.value > cost);
	    emit ToCorex(to, (msg.value - cost) * crxeth);
    }

    function toEthereum(address payable dst, uint256 val) external payable {
	    require(msg.sender == owner);
	    dst.transfer(val);
	    emit ToEthereum(dst, val);
    }
}

```

### TEO сүлжээн дээрх ухаалаг гэрээ

CRX2ETH гэрээ нь CRX-ийг ETH болгох мөн Ethereum сүлжээнээс орж ирсэн захиалгын CRX-ийг түгээх үйлдлүүдийг хариуцна. Уг гэрээ нь дотроо гэрээний эзэн owner, CRX-ийг ETH болгох ханш ethcrx, Ethereum сүлжээн дээр хийгдэх гүйлгээний хураамж cost зэргийг агуулна.&#x20;

* **toEthereum** үйлдлийг CRX-ийг ETH болгоход ашиглана. Ethereum сүлжээн дээрх хаягийг дамжуулах ба уг үйлдлийг хийхдээ CRX шилжүүлэх ёстой. Шилжүүлсэн CRX-ээс ETH сүлжээн дээр хийгдэх гүйлгээний хураамжыг хасаж ethcrx ханшаар хөрвүүлэн ToEthereum event үүсгэн блокчэйнд хадгална.
* **toCorex** үйлдлийг зөвхөн гэрээний эзэн дуудна. Ethereum сүлжээнээс CRX-ийг захиалах үед гүүрээр дамжин корэкс сүлжээнд, захиалсан CRX-ийг түгээхэд хэрэглэнэ.

```solidity
pragma solidity ^0.5.0;

contract CRX2ETH {

    uint public cost;                // ethereum chain дээр гүйлгээ хийх үнэ
    uint public ethcrx;
    address public owner;
    
    event ToCorex(address indexed dst, uint val);
    event ToEthereum(address indexed dst, uint val);

    constructor() public {
        owner = msg.sender;
        cost = 6077.15 ether;
        ethcrx = 1.64e-6 ether;
    }

    function() external payable {
    }
    
    function toCorex(address payable dst, uint val) external payable {
	require(msg.sender == owner);
	dst.transfer(val);
	emit ToCorex(dst, val);
    }

    function toEthereum(address payable dst, uint val) external payable {
	require(msg.value > cost);
        emit ToEthereum(dst, (msg.value - cost) * ethcrx);
    }
}

```

### Ухаалаг гэрээний event сонсох

Ухаалаг гэрээний event-үүд блокчэйнд хадгалагдан үлддэг тул хэзээч гэсэн тэр event-ийг ухаж үзэх боломжтой гэсэн үг юм. Ухаалаг гэрээний үүсгэсэн event-ийг web3js ашиглан хоёр янзаар сонсох боломжтой.

#### 1. Өнгөрсөн event-үүдийг унших

Contract тохиолдол үүсгэсний дараагаар `getPastEvents` функцийг ашиглан тухайн гэрээний бүх event-үүдийг шүүн харах боломжтой. Доорх жишээнд гэрээний `ToCorex` event-ийг блок 0-ээс эхлэн хамгийн сүүлийн блок хүртэл түүж харж байна. Маш их өгөгдөл буцаах боломжтой бөгөөд удаан ажиллана. Энэ фукцийн нэг дутагдалтай тал бол event-үүдийг индекслэх системийг гүүр дээр хэрэгжүүлж өгөх шаардлагатай.

```javascript
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,                  //Number || "earliest" || "pending" || "latest"
    toBlock: 'latest'
};

ETH2CRX.getPastEvents('ToCorex', options)
    .then(results => console.log(results))
    .catch(err => throw err);
```

#### 2. Гэрээний event функцийг ашиглах

Гэрээний event функцийг ашиглан гэрээнээс гарсан өөрчлөлтүүдийг чагнах боломжтой. Доор жишээнд `ToCorex` event-ийг сонсох ба `data` дээр шинээр үүсгэгдсэн event-ийн мэдээлэл ирдэг. Уг арга ажиллахын тулд ABI зөв байх ёстойг анхаарна уу.

```javascript
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))
```

### Ухаалаг гэрээний функцийг дуудах

Ethereum сүлжээн дээр `ToCorex` event-ийг сонсон ирсэн тохиолдолд `eth2crx_process` функцийг дуудна. Уг функц нь TEO сүлжээн дээрх CRX2ETH гэрээний `toCorex` функцийг дуудаж зохиох хэмжээний CRX-ийг харгалзах хаягт шилжүүлнэ. Гүйлгээний хураамж гэрээний эзнээс гарах бөгөөд мөнгөн дүн нь гэрээнд агуулагдах CRX-ээс шилжүүлэгдэх болно.

```javascript
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)
	}
    }
}

```

Дээрх жишээнд агуулагдаж буй гүйлгээ хийх`transfer` функцийн кодыг доор оруулав.

```javascript
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 файлуудад харуулав.&#x20;

* client.js - Блокчэйнтэй холбогдох хэсгийг агуулах код
* main.js - Гүүрийг хэрэгжүүлсэн код

{% code title="client.js" %}

```javascript
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;
```

{% endcode %}

{% code title="main.js" %}

```javascript
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');
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.teo.mn/development/blockchain-bridge.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
