Từ sau những năm tháng rực rỡ của Bitcoin đã mở ra một thời kì blockchain mới với hàng trăm loại blockchain khác nhau tiêu biểu như ETH, NEO, TRON, … Mỗi blockchain sinh ra để cải tiến một nhược điểm nào đó của mô hình blockchain cũ như tăng tốc độ, tăng tính ứng dụng, có thể lập trình, tích kiệm tài nguyên. Mở ra những tiềm năng phát triển hứa hẹn có thể áp dụng blockchain trong cuộc sống thường ngày của chúng ta. Tuy nhiên chính sự phát triển theo hướng đó dẫn đến việc giữa các blockchain bị cô lập với nhau. Tuy rằng chúng ta hoàn toàn có thể đưa các token lên các sàn tập trung để exchange nhưng như thế lại mang tính tập trung hơn nữa tài khoản trên sàn cũng là do sàn quản lý như vậy thật thiếu an toàn. Cộng đồng đã mơ về một sàn phi tập trung nơi mà mọi nền tảng blockchain có thể exchange mà ko có một bên thư ba nào can thiệp vào , chính vì thế mà Hashed TimeLock Contract ra đời .
Vấn đề
Khi hai người muốn trao đổi 2 vật phẩm thì sẽ làm thế nào ? Người A gửi cho người B rồi người B gửi cho người A . Như vậy thì nhỡ đâu người B nhận được rồi sau đó bùng luôn thì sao. Một cách khác đó là nhờ một người thứ 3 , khi cả người A và B đưa vật phẩm cho người thứ 3 sau đó người thứ 3 sẽ đưa lại cho cả người B và A . Nhưng nhỡ đâu người thứ 3 cầm rồi chạy mất thì sao. Và thực trạng hiện nay thì cách trade ở một số sàn giao dịch tập trung như Binance Okex đều là như thế. Chính vì thế mà ng ta mong muốn có một sàn phi tập trung từ rất lâu rồi . Chắc một vài bạn sẽ tự hỏi chẳng phải viết 1 cái smart contract trên eth là giải quyết đc vấn đề người thứ 3 sao ? . Đúng thế nhưng nếu ng dùng muốn exchange giữa 2 loại blockchain khác hẳn nhau thì sao ? Và hashed timelock contract là 1 câu trả lời cho câu hỏi này .
Hashed TimeLock Contract là gì ?
Hashed TimeLock Contract ( HTLC ) là một loại smart contract được sử dụng để trao đổi các loại coin, token khác nhau mà không cần phải cần đến bên thứ ba cũng như không phải lo lắng về các rủi ro scam. Bằng cách cho phép thực hiện giao dịch trong một giới hạn thời gian nhất định. Cụ thể hơn là , người nhận giao dịch HTLC phải xác nhận khoản thanh toán bằng cách gửi một đoạn key mã hóa để xác thực trong một khung thời gian cụ thể (tính bằng số khối). Nếu người nhận từ chối hoặc không yêu cầu thanh toán, số tiền sẽ được trả lại cho người gửi ban đầu.
Có hai yếu tô quan trọng trong HTLC đó là Hashlock và timelock :
Hashlock: người đầu tiên tạo một sẽ tạo một secret sau đó dùng một hàm mã hóa để hash ra một mã gọi là hashlock.
Timelock: là một chức năng hạn chế việc giao dịch trong một thời điểm cụ thể (tính bằng số block) .
Luồng hoạt động
Kịch bản của chúng ta sẽ gồm hai người Alice người giữ Ethereum và Bob người giữ Bitcoin . Hai người này sẽ thực hiện trao đổi Eth và BTC mà không cần phải tin tưởng lẫn nhau . Quá trình này bao gồm hai bên và bốn tài khoản, vì vậy quá trình sẽ gồm :
Alice 2 tài khoản : Tài khoản gửi ETH và tài khoản nhận BTC
Bob 2 tài khoản : Tài khoản gửi BTC và tài khoản nhận ETH
Quá trình sẽ diến ra như sau :
- Alice chọn một số hoặc 1 chuỗi kí tự ngẫu nhiên đặt là secret sau đó sử dụng một hàm hash để tạo ra hasklock
- Taọ một Lock trên contract của Eth, bao gồm các thông tin cần thiết như hashlock, timelock ,input amount , receiver, sender ,…
- Gửi cho Bob hashlock đó
- Bob cũng tạo một Lock trên BTC gồm hachlock mà Alice gửi ,timelock, input amount, receiver, sender,…
- Alice sẽ sử dụng secret để giải mã Lock của Bob để nhận BTC đồng thời secret sẽ được public lên mạng và Bob sẽ biết
- Bob sửa dụng secret đã được public để mở Lock của Alice và nhận được ETH
Demo
Mình sẽ demo code một chiều từ ETH
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | pragma solidity <span class="token operator">^</span><span class="token number">0.5</span><span class="token number">.0</span><span class="token punctuation">;</span> pragma experimental ABIEncoderV2<span class="token punctuation">;</span> contract HashTimeLock <span class="token punctuation">{</span> <span class="token function">mapping</span><span class="token punctuation">(</span><span class="token parameter">bytes32</span> <span class="token operator">=></span> LockContract<span class="token punctuation">)</span> <span class="token keyword">public</span> contracts<span class="token punctuation">;</span> <span class="token comment">// / - WITHDRAWN</span> <span class="token comment">// INVALID - ACTIVE |</span> <span class="token comment">// - EXPIRED - REFUNDED</span> uint256 <span class="token keyword">public</span> constant <span class="token constant">INVALID</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// Uninitialized swap -> can go to ACTIVE</span> uint256 <span class="token keyword">public</span> constant <span class="token constant">ACTIVE</span> <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">// Active swap -> can go to WITHDRAWN or EXPIRED</span> uint256 <span class="token keyword">public</span> constant <span class="token constant">REFUNDED</span> <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token comment">// Swap is refunded -> final state.</span> uint256 <span class="token keyword">public</span> constant <span class="token constant">WITHDRAWN</span> <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span> <span class="token comment">// Swap is withdrawn -> final state.</span> uint256 <span class="token keyword">public</span> constant <span class="token constant">EXPIRED</span> <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span> <span class="token comment">// Swap is expired -> can go to REFUNDED</span> struct LockContract <span class="token punctuation">{</span> uint256 inputAmount<span class="token punctuation">;</span> uint256 outputAmount<span class="token punctuation">;</span> uint256 expiration<span class="token punctuation">;</span> uint256 status<span class="token punctuation">;</span> bytes32 hashLock<span class="token punctuation">;</span> address payable sender<span class="token punctuation">;</span> address payable receiver<span class="token punctuation">;</span> string outputNetwork<span class="token punctuation">;</span> string outputAddress<span class="token punctuation">;</span> <span class="token punctuation">}</span> event <span class="token function">Withdraw</span><span class="token punctuation">(</span> bytes32 indexed id<span class="token punctuation">,</span> bytes32 secret<span class="token punctuation">,</span> bytes32 hashLock<span class="token punctuation">,</span> address indexed sender<span class="token punctuation">,</span> address indexed receiver <span class="token punctuation">)</span><span class="token punctuation">;</span> event <span class="token function">Refund</span><span class="token punctuation">(</span> bytes32 indexed id<span class="token punctuation">,</span> bytes32 hashLock<span class="token punctuation">,</span> address indexed sender<span class="token punctuation">,</span> address indexed receiver <span class="token punctuation">)</span><span class="token punctuation">;</span> event <span class="token function">NewContract</span><span class="token punctuation">(</span> uint256 inputAmount<span class="token punctuation">,</span> uint256 outputAmount<span class="token punctuation">,</span> uint256 expiration<span class="token punctuation">,</span> bytes32 indexed id<span class="token punctuation">,</span> bytes32 hashLock<span class="token punctuation">,</span> address indexed sender<span class="token punctuation">,</span> address indexed receiver<span class="token punctuation">,</span> string outputNetwork<span class="token punctuation">,</span> string outputAddress <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">newContract</span><span class="token punctuation">(</span> <span class="token parameter">uint256 outputAmount<span class="token punctuation">,</span> uint256 expiration<span class="token punctuation">,</span> bytes32 hashLock<span class="token punctuation">,</span> address payable receiver<span class="token punctuation">,</span> string calldata outputNetwork<span class="token punctuation">,</span> string calldata outputAddress</span> <span class="token punctuation">)</span> external payable <span class="token punctuation">{</span> address payable sender <span class="token operator">=</span> msg<span class="token punctuation">.</span>sender<span class="token punctuation">;</span> uint256 inputAmount <span class="token operator">=</span> msg<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>expiration <span class="token operator">></span> block<span class="token punctuation">.</span>timestamp<span class="token punctuation">,</span> <span class="token string">'INVALID_TIME'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>inputAmount <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">'INVALID_AMOUNT'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> bytes32 id <span class="token operator">=</span> <span class="token function">sha256</span><span class="token punctuation">(</span> abi<span class="token punctuation">.</span><span class="token function">encodePacked</span><span class="token punctuation">(</span>sender<span class="token punctuation">,</span> receiver<span class="token punctuation">,</span> inputAmount<span class="token punctuation">,</span> hashLock<span class="token punctuation">,</span> expiration<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>contracts<span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">.</span>status <span class="token operator">==</span> <span class="token constant">INVALID</span><span class="token punctuation">,</span> <span class="token string">"SWAP_EXISTS"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> contracts<span class="token punctuation">[</span>id<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">LockContract</span><span class="token punctuation">(</span> inputAmount<span class="token punctuation">,</span> outputAmount<span class="token punctuation">,</span> expiration<span class="token punctuation">,</span> <span class="token constant">ACTIVE</span><span class="token punctuation">,</span> hashLock<span class="token punctuation">,</span> sender<span class="token punctuation">,</span> receiver<span class="token punctuation">,</span> outputNetwork<span class="token punctuation">,</span> outputAddress <span class="token punctuation">)</span><span class="token punctuation">;</span> emit <span class="token function">NewContract</span><span class="token punctuation">(</span> inputAmount<span class="token punctuation">,</span> outputAmount<span class="token punctuation">,</span> expiration<span class="token punctuation">,</span> id<span class="token punctuation">,</span> hashLock<span class="token punctuation">,</span> sender<span class="token punctuation">,</span> receiver<span class="token punctuation">,</span> outputNetwork<span class="token punctuation">,</span> outputAddress <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">withdraw</span><span class="token punctuation">(</span><span class="token parameter">bytes32 id<span class="token punctuation">,</span> bytes32 secret</span><span class="token punctuation">)</span> external <span class="token punctuation">{</span> LockContract storage c <span class="token operator">=</span> contracts<span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>status <span class="token operator">==</span> <span class="token constant">ACTIVE</span><span class="token punctuation">,</span> <span class="token string">"SWAP_NOT_ACTIVE"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>expiration <span class="token operator">></span> block<span class="token punctuation">.</span>timestamp<span class="token punctuation">,</span> <span class="token string">"INVALID_TIME"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>hashLock <span class="token operator">==</span> <span class="token function">sha256</span><span class="token punctuation">(</span>abi<span class="token punctuation">.</span><span class="token function">encodePacked</span><span class="token punctuation">(</span>secret<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token string">"INVALID_SECRET"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> c<span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">WITHDRAWN</span><span class="token punctuation">;</span> c<span class="token punctuation">.</span>receiver<span class="token punctuation">.</span><span class="token function">transfer</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>inputAmount<span class="token punctuation">)</span><span class="token punctuation">;</span> emit <span class="token function">Withdraw</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> secret<span class="token punctuation">,</span> c<span class="token punctuation">.</span>hashLock<span class="token punctuation">,</span> c<span class="token punctuation">.</span>sender<span class="token punctuation">,</span> c<span class="token punctuation">.</span>receiver<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">refund</span><span class="token punctuation">(</span><span class="token parameter">bytes32 id</span><span class="token punctuation">)</span> external <span class="token punctuation">{</span> LockContract storage c <span class="token operator">=</span> contracts<span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>status <span class="token operator">==</span> <span class="token constant">ACTIVE</span><span class="token punctuation">,</span> <span class="token string">"SWAP_NOT_ACTIVE"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>expiration <span class="token operator"><=</span> block<span class="token punctuation">.</span>timestamp<span class="token punctuation">,</span> <span class="token string">"INVALID_TIME"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> c<span class="token punctuation">.</span>status <span class="token operator">=</span> <span class="token constant">REFUNDED</span><span class="token punctuation">;</span> c<span class="token punctuation">.</span>sender<span class="token punctuation">.</span><span class="token function">transfer</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span>inputAmount<span class="token punctuation">)</span><span class="token punctuation">;</span> emit <span class="token function">Refund</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> c<span class="token punctuation">.</span>hashLock<span class="token punctuation">,</span> c<span class="token punctuation">.</span>sender<span class="token punctuation">,</span> c<span class="token punctuation">.</span>receiver<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token parameter">bytes32<span class="token punctuation">[</span><span class="token punctuation">]</span> memory ids</span><span class="token punctuation">)</span> <span class="token keyword">public</span> view <span class="token function">returns</span> <span class="token punctuation">(</span><span class="token parameter">uint256<span class="token punctuation">[</span><span class="token punctuation">]</span> memory</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> uint256<span class="token punctuation">[</span><span class="token punctuation">]</span> memory result <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">uint256</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span>ids<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>uint256 index <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> index <span class="token operator"><</span> ids<span class="token punctuation">.</span>length<span class="token punctuation">;</span> index<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> result<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">getSingleStatus</span><span class="token punctuation">(</span>ids<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> result<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">getSingleStatus</span><span class="token punctuation">(</span><span class="token parameter">bytes32 id</span><span class="token punctuation">)</span> <span class="token keyword">public</span> view <span class="token function">returns</span> <span class="token punctuation">(</span><span class="token parameter">uint256 result</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> LockContract memory tempContract <span class="token operator">=</span> contracts<span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> tempContract<span class="token punctuation">.</span>status <span class="token operator">==</span> <span class="token constant">ACTIVE</span> <span class="token operator">&&</span> tempContract<span class="token punctuation">.</span>expiration <span class="token operator"><</span> block<span class="token punctuation">.</span>timestamp <span class="token punctuation">)</span> <span class="token punctuation">{</span> result <span class="token operator">=</span> <span class="token constant">EXPIRED</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> result <span class="token operator">=</span> tempContract<span class="token punctuation">.</span>status<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Contract sẽ gồm 3 hàm chính đó là newContract, withdraw, refund và ngoài ra còn 2 hàm check status của Lock
- newContract : đây là hàm để tạo 1 Lock gồm các tham số cần thiết . sau khi tạo xong sẽ tạo ra một emit NewContract public lên mạng
- withdraw : đây là hàm để cho ng nhận điền id của Lock và secret vào . Đầu tiên sẽ check thời gian xem đã hết hạn chưa, sau đó sử dụng hàm sha256 hash rồi so sánh vs hashlock nếu đúng thì giao dịch sẽ thực hiện và sau đó sẽ public private key thông qua emit
- refund : hàm này chỉ chạy khi đã quá thời gian mà khi khởi tạo Lock vs mục đích cho người tạo rút lại tiền
Contract sẽ gồm 5 trạng thái
- INVALID : đây là trạng thái mà contracts[id] đã tồn tại . vì id được lấy là hash của sender, receiver, inputAmount, hashLock, expiration nên vẫn có thể sẽ trùng . Và nếu trùng thì sẽ ko tạo đc Lock
- ACTIVE : đây là trạng thái mà contracts[id] hợp lệ .
- WITHDRAWN : sau khi người nhận vào rút tiền thì Lock sẽ chuyển qua trạng thái withdrawn
- EXPIRED : đây là trạng thái người nhận không vào rút và đã quá khoảng thời gian qui định (expiration)
- REFUNDED : chỉ khi contract ở trạng thái expired thì người tạo mới có thể vào rút lại khoản tiền của mình và sau khi rút xong thì Lock sẽ về trạng thái refunded
ngoài ra còn 2 hàm để check status cũng như 3 emit để bắt các sự kiện trong contract .Quan trọng nhất là 2 emit đó là NewContract và withdrawn vì newContract sẽ public Id của Lock và withdrawn sẽ public secret của người tạo lên mạng .
Tổng kết
Mình chỉ giải thích một cầu từ eth thôi còn phía BTC cũng tương tự như vậy vẫn sẽ cần 3 hàm cơ bản là newContract , withdraw và refund và tuân thủ các quy tắc về time cũng như có các sự kiện public ra mạng khi có người thao tác . Ở bài viết tiếp theo mình sẽ viết về Market maker để khi kết hợp lại thì chúng ta có 1 sàn phi tập trung vs heart là htlc .