Menu

  • Home
  • Trending
  • Recommended
  • Latest

分類

  • #2021 新年特輯
  • 100天區塊鏈挑戰
  • 2019 台灣區塊鏈產業指南
  • 2020 台灣區塊鏈產業年鑑
  • 2022 台灣年度最影響力人物榜
  • 2023 台灣年度影響力人物榜
  • 2023 新春特輯
  • 2024 TON Hacker House
  • 2024新春特輯
  • ABS 2018 專題報導
  • AI
  • CBDC是什麼?為何全球都在積極研究、有什麼優點與隱憂
  • Cefi
  • dao
  • dApps
  • defi
  • DePIN 如何開啟去中心化物理網路革命?
  • Entertainment
  • EOS
  • EOS insights
  • Gaming
  • Howto & Style
  • ICO
  • JiaJia
  • Layer 2
  • Libra
  • Movie
  • Music
  • News
  • nft
  • Plurality 多元宇宙
  • Starknet 空投落地,後續帶來什麼影響?
  • TON的崛起之路》背靠 Telegram 如何實現 Web3 大規模應用?
  • Uncategorized
  • Web3.0
  • 中國
  • 亞太
  • 交易所
  • 人物專訪
  • 以太坊
  • 以太坊
  • 以太坊 Dencun 坎昆升級將臨,你需要知道的所有事
  • 以太坊再質押協議為何成為最熱門賽道?
  • 供應鏈
  • 保險
  • 債券
  • 元宇宙
  • 全台最大詐騙案!Ace交易所涉垃圾幣詐騙
  • 全球加密貨幣監管最新動態統整
  • 其他國家
  • 其他幣別
  • 分散式帳本技術
  • 創投
  • 加密貨幣「詐騙手法」整理,學習如何保護你的資產
  • 加密貨幣市場
  • 區塊鏈平台
  • 區塊鏈新手全攻略,你需要知道的加密貨幣基礎
  • 區塊鏈新手教學
  • 區塊鏈活動
  • 區鍵禧
  • 即時新聞
  • 台灣
  • 哈希派
  • 國際組織報告
  • 多元宇宙Plurality有多重要?未來20年人類躍進關鍵
  • 央行
  • 娛樂平台
  • 安全
  • 專欄作者
  • 巴拉區塊事
  • 市場分析
  • 幣安與美國司法部達成 43 億美元和解,CZ認罪
  • 影片測試的分類
  • 快訊
  • 技術
  • 抓住空投爆擊!值得埋伏的項目、互動教學總整理
  • 投資分析
  • 挖礦
  • 推薦閱讀
  • 搶先看
  • 支付
  • 政府報告
  • 數位產權
  • 數據報告
  • 概念
  • 歐洲
  • 比特幣
  • 比特幣現貨ETF上市,真帶來了增量資金?
  • 比特幣第四次減半將臨,行情怎麼走?
  • 比特幣銘文大爆發,Oridinal 如何改變 BTC 生態?
  • 比特彭
  • 汪彪
  • 法規
  • 測試網
  • 灰度
  • 物聯網
  • 犯罪
  • 獨立觀點
  • 瑞波
  • 環境永續
  • 社交
  • 私人機構報告
  • 稅務
  • 穩定幣
  • 管制
  • 美國
  • 肺炎
  • 能源
  • 訴訟
  • 評級報告
  • 財金哥 & 區塊妹
  • 身份驗證
  • 遊戲
  • 鄧庶杭
  • 金融市場
  • 銀行
  • 錢包

Subscriptions

  • 零壹財經 01 binary
    01 Binary
  • 0xdt
  • 0xJigglypuff
  • aaaaYYYY
  • ABCDELabs

Recent News

  • 圖解多元宇宙》V神、Glen力推的Plurality是什麼?為何協作技術是人類社會進步關鍵
  • 精選文章搶先看!動區登入Access質押訂閱服務,解鎖寶貴資訊快人一步
  • ABS獨家專訪》Gitcoin共同創辦人Scott:台灣是現實與Web3治理的重要交匯點
動區動趨-最具影響力的區塊鏈新聞媒體
  • Home
    • Home Layout 1
    • Home Layout 2
    • Home Layout 3
  • Browse
    • News
    • Movie
    • Music
    • Technology
    • Howto & Style
    • Entertainment
    • Gaming
  • Features
    • Youtube Video
    • Vimeo Video
    • Dailymotion Video
    • Self-hosted Video
    • User Profile
    • Playlists
    • User-created Playlist
    • Favorite Playlist (Private)
    • Watch Later Playlist (Private)
    • All JNews Features
No Result
View All Result
  • Login
  • Register
UPLOAD
動區動趨-最具影響力的區塊鏈新聞媒體
No Result
View All Result
Home 技術

Solidity閃電貸實現方式,與Move、Rust有何不同?

Beosin區塊鏈安全審計 by Beosin區塊鏈安全審計
2023-10-30
in 技術
521 16
0
Solidity閃電貸實現方式,與Move、Rust有何不同?
738
SHARES
3.4k
VIEWS
Share on FacebookShare on Twitter

對比三種語言的閃電貸流程,由於語言的特性,在實現方式上有所不同。
(前情提要:Beosin:Move VM先前毀滅級漏洞,可讓Sui、Aptos「崩潰、甚至硬分叉」 )
(背景補充:Metamask開發公司ConsenSys:給 Solidity 開發者的 16 個安全建議 )

本文目錄

  • RelatedPosts
  • 圖解多元宇宙》V神、Glen力推的Plurality是什麼?為何協作技術是人類社會進步關鍵
  • 6 Sci-fi Gadgets in Movie We Wish Actually Existed
  • Tesla’s Chinese factory just delivered its first cars
  • Solidity 相關閃電貸:
  • Move 相關閃電貸:
  • Rust 相關閃電貸:

 

RelatedPosts

圖解多元宇宙》V神、Glen力推的Plurality是什麼?為何協作技術是人類社會進步關鍵

6 Sci-fi Gadgets in Movie We Wish Actually Existed

Tesla’s Chinese factory just delivered its first cars

閃電貸是一種無抵押借款的服務,由於其擁有無需抵押便能借出資金的特性,使得資金利用率大大提高。在常見的以太坊閃電貸中,是通過以太坊交易機制來保證可以進行無抵押借出資金,以太坊中一個交易可以包含很多步驟,如:借款、兌換、使用、還款等,所有的步驟相輔相成,若其中某一個或多個步驟出現錯誤,都將導致本次的整個交易被回滾。

隨著區塊鏈生態發展,出現了大量公鏈以及合約程式語言,例如:除了 Solidity 之外最常見的 Move 和 Rust,這些合約程式語言有本質上的區別,框架與程式設計理念也有所不同, 本篇文章我們來對比一下 Solidity 閃電貸實現方式與 Move 以及 Rust 閃電貸實現方式有何不同,同時可以初步瞭解一下各種語言的程式設計理念。

延伸閱讀:解析閃電貸》今年DeFi被盜最高破1.2億鎂,去中心化金融成「駭客」斂財神器?

Solidity 相關閃電貸:

Solidity 的閃電貸是基於 Solidity 支援動態呼叫這一特性來設計的,何為動態呼叫,也就是 solidity 支援在呼叫一個函式的過程中,動態傳入需要呼叫的地址,如下例程式碼。每次呼叫都可以傳入不同的地址,根據這個特點,便出現了 solidity 閃電貸的實現邏輯。

function callfun(address addr) public {

addr.call();

}

如下程式碼,將閃電貸抽象成了 3 個核心功能,

  1. 首先直接將資金發送給呼叫者;
  2. 再呼叫呼叫者合約,從而讓呼叫者使用這些資金;
  3. 呼叫者使用結束,檢查是否歸還資金以及手續費,如果檢查失敗則回滾交易。(此處也可以直接使用 transferfrom 函式將呼叫則資金轉移回來)

function flashloan(uint amount, address to) {

transfer (to, amount); // 傳送資金給呼叫者

to.call ();// 呼叫呼叫者的合約函式

check ();// 檢查是否歸還資金

}

如下圖,為 Solidity 語言中閃電貸的實現流程:

下列程式碼為真實專案 Uniswap 閃電貸邏輯。程式碼示例:

function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {

require(amount0Out > 0 || amount1Out > 0, ‘UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT’);

(uint112 _reserve0, uint112 _reserve1,) = getReserves();

require(amount0Out < _reserve0 && amount1Out < _reserve1, ‘UniswapV2: INSUFFICIENT_LIQUIDITY’); uint balance0; uint balance1; { address _token0 = token0; address _token1 = token1; require(to != _token0 && to != _token1, ‘UniswapV2: INVALID_TO’); /** 將資金轉給使用者 **/ if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out);

if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out);

/** 呼叫使用者指定的目標函式 **/

if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);

balance0 = IERC20(_token0).balanceOf(address(this));

balance1 = IERC20(_token1).balanceOf(address(this));

}

uint amount0In = balance0 > _reserve0 – amount0Out ? balance0 – (_reserve0 – amount0Out) : 0;

uint amount1In = balance1 > _reserve1 – amount1Out ? balance1 – (_reserve1 – amount1Out) : 0;

require(amount0In > 0 || amount1In > 0, ‘UniswapV2: INSUFFICIENT_INPUT_AMOUNT’);

{

uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));

uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));

/** 檢查使用者是否歸還資金以及手續費 **/

require(balance0Adjusted.mul(balance1Adjusted)>=uint(_reserve0).mul(_reserve1).mul(1000**2), ‘UniswapV2: K’);

}

_update(balance0, balance1, _reserve0, _reserve1);

emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);

}

Move 相關閃電貸:

Move 閃電貸和 solidity 設計思想不同,move 中沒有動態呼叫這一個特性,在所有函式呼叫過程之前,都必須確定呼叫流程,明確呼叫合約地址是什麼,所以無法像 solidity 裡面那樣動態傳入地址再進行呼叫。

那麼 move 能實現閃電貸功能嗎?當然可以,move 的特性使得人們設計出與 solidity 實現方式不同的閃電貸。

在 Move 中,將資料和執行程式碼分離,造就了 Move VM 獨特的資源 – 模組模型。在這種模型中,不允許資源在交易結束時未被銷燬或者儲存在全域性儲存中,因此 Move 中的資源存在一種特殊的結構體 —— 燙手山芋(Hot Potato),它是一個沒有任何能力修飾符的結構體,因此它只能在其模組中被打包和解包。Move 能力詳情。

因此在 move 語言中的閃電貸實現,巧妙地利用了這種模式,將閃貸和還款操作抽象為兩個函式進行處理,中間產生借貸資源記錄借貸情況,該資源並沒任何能力,只能夠在還款函式中通過解包的方式將借貸資源給消耗掉,因此借貸操作必須和還款操作繫結在同一個操作中,否則閃電貸交易就會失敗。

如下圖,為 move 語言中閃電貸的實現流程。

如下程式碼,loan 與 repay 兩個函式相結合便可以實現閃電貸。需要使用閃電貸服務的使用者,先呼叫 loan 函式申請借款。函式會首先判斷是否有足夠的資金提供借款,隨後將資金髮送給呼叫者,計算好費用後,建立一個沒有任何能力的資源「receipt」並返回給呼叫者。呼叫者在自己的合約中使用借貸的資金,最後需要將「receipt」返還到 repay 函式,並且附帶歸還的資金。在 repay 函式中,首先將「receipt」資源解構,以確保交易成功執行,隨後判斷使用者歸還資金是否與之前計算好的資金數量相同,最後完成整個交易。

程式碼示例:

struct Receipt {

flash_lender_id: ID,

repay_amount: u64

}

public fun loan(self: &mut FlashLender, amount: u64, ctx: &mut TxContext):

(Coin, Receipt) {

let to_lend = &mut self.to_lend;

assert!(balance::value(to_lend) >= amount, ELoanTooLarge);

let loan = coin::take(to_lend, amount, ctx);

let repay_amount = amount + self.fee;

let receipt = Receipt { flash_lender_id: object::id(self), repay_amount };

(loan, receipt)

}

public fun repay(self: &mut FlashLender, payment: Coin, receipt: Receipt) {

let Receipt { flash_lender_id, repay_amount } = receipt;

assert!(object::id(self) == flash_lender_id, ERepayToWrongLender);

assert!(coin::value(&payment) == repay_amount, EInvalidRepaymentAmount);

coin::put(&mut self.to_lend, payment)

}

Rust 相關閃電貸:

Rust 由於其提供記憶體安全、併發安全和零成本抽象等特性。也被用在了區塊鏈智慧合約語言開發中,接下來我們以 Solana 智慧合約(Program)為例講解使用 Rust 開發實現的閃電貸。

Solana VM 亦將資料和執行程式碼進行了分離,使得一份執行程式碼可以處理多份資料副本,但與 Move 不同的是,陣列帳戶是通過程式派生的方式完成的,並且沒有類似於 Move 特性的限制。因此 Solana Rust 不能夠使用 Move 的方式實現閃電貸,並且 Solana Rust 動態呼叫指令(等同於理解為合約的函式)遞迴深度限制為 4,使用 Solidity 動態呼叫的方式同樣不可取。但在 Solana 中每個指令(instruction)呼叫在交易中是原子型別的,因此在一筆交易中可以在一個指令中檢查是否存在另一個指令。而 Solana 中的閃電貸依賴此了特性,Solana 閃電貸在閃貸的指令中將檢查閃電貸交易中是否存在還款的指令,並檢查還款的數量是否正確。

如下圖,為 Rust 語言中閃電貸的實現流程:

程式碼示例:

pub fn borrow(ctx: Context, amount: u64) -> ProgramResult {

msg!(“adobe borrow”);

if ctx.accounts.pool.borrowing {

return Err(AdobeError::Borrowing.into());

}

let ixns = ctx.accounts.instructions.to_account_info();

// make sure this isnt a cpi call

let current_index = solana::sysvar::instructions::load_current_index_checked(&ixns)? as usize;

let current_ixn = solana::sysvar::instructions::load_instruction_at_checked(current_index, &ixns)?;

if current_ixn.program_id != *ctx.program_id {

return Err(AdobeError::CpiBorrow.into());

}

let mut i = current_index + 1;

loop {

// 遍歷交易序列中的指令,

if let Ok(ixn) = solana::sysvar::instructions::load_instruction_at_checked(i, &ixns) {

// 查詢是否同時呼叫了該程式的中還款指令(repay)

if ixn.program_id == *ctx.program_id

// 檢查 invoke data 中 函式簽名

&& u64::from_be_bytes(ixn.data[..8].try_into().unwrap()) == REPAY_OPCODE

&& ixn.accounts[2].pubkey == ctx.accounts.pool.key() {

// 檢查 函式 invoke data 中 amount 數量是否正確

if u64::from_le_bytes(ixn.data[8..16].try_into().unwrap()) == amount {

break;

} else {

return Err(AdobeError::IncorrectRepay.into());

}

} else {

i += 1;

}

}else {

return Err(AdobeError::NoRepay.into());

}

}

let state_seed: &[&[&[u8]]] = &[&[

&State::discriminator()[..],

&[ctx.accounts.state.bump],

]];

let transfer_ctx = CpiContext::new_with_signer(

ctx.accounts.token_program.to_account_info(),

Transfer {

from: ctx.accounts.pool_token.to_account_info(),

to: ctx.accounts.user_token.to_account_info(),

authority: ctx.accounts.state.to_account_info(),

},

state_seed,

);

//cpi 轉帳

token::transfer(transfer_ctx, amount)?;

ctx.accounts.pool.borrowing = true;

Ok(())

}

// REPAY

// receives tokens

pub fn repay(ctx: Context, amount: u64) -> ProgramResult {

msg!(“adobe repay”);

let ixns = ctx.accounts.instructions.to_account_info();

// make sure this isnt a cpi call

let current_index = solana::sysvar::instructions::load_current_index_checked(&ixns)? as usize;

let current_ixn = solana::sysvar::instructions::load_instruction_at_checked(current_index, &ixns)?;

if current_ixn.program_id != *ctx.program_id {

return Err(AdobeError::CpiRepay.into());

}

let state_seed: &[&[&[u8]]] = &[&[

&State::discriminator()[..],

&[ctx.accounts.state.bump],

]];

let transfer_ctx = CpiContext::new_with_signer(

ctx.accounts.token_program.to_account_info(),

Transfer {

from: ctx.accounts.user_token.to_account_info(),

to: ctx.accounts.pool_token.to_account_info(),

authority: ctx.accounts.user.to_account_info(),

},

state_seed,

);

// 還款

token::transfer(transfer_ctx, amount)?;

// 更新帳本狀態

ctx.accounts.pool.borrowing = false;

Ok(())

}

對比三種語言的閃電貸流程,均為借款 -> 使用 -> 還款三步,只是由於語言的特性,在實現方式上有所不同。

Solidity 支援動態呼叫,所以可以在單個函式中完成整個交易;

Move 不支援動態呼叫,由於資源的特性,需要使用兩個函式進行借款和還款邏輯;

Rust(Solana)能支援動態呼叫,但是僅支援 4 層 CPI 呼叫,使用 CPI 實現閃電貸將產生侷限性,但是 Solana 每個指令都是原子型別,並且支援指令自省,因此使用指令自省的方式實現閃電貸是較好的方式。

📍相關報導📍

 SUI 遭爆3月秘密修復「十億美元安全漏洞」,可讓駭客閃電貸攻擊..

閃電網路爆重大安全漏洞!比特幣核心開發者退出開發:從底層改才有救

Visa搶聘區塊鏈工程師!須懂L1、L2,精熟Solidity與Rust語言

Tags: MoveRustSolidity程式語言閃電貸

Recommended videos

3:01

John Mayer Shares New Single “Carry Me Away”

2.5k Views
2024-06-16
    8:53

    Death Stranding – Release Date Reveal Trailer

    2.5k Views
    2024-07-02
      4:31

      Only Beyoncé Could Make Opera Gloves Cool

      2.5k Views
      2024-07-12
        4:33

        The Night Comes For Us – Official Trailer [HD]

        2.5k Views
        2024-07-18
          Show More
          Copyright (c) 2019 by Jegtheme.
          • About
          • Buy JNews
          • Request A Demo
          • Contact
          No Result
          View All Result
          • Account
          • BlockTempo Beginner – 動區新手村
          • Change Password
          • Forgot Password?
          • Home 1
          • Home 2
          • Home 3
          • Jin-homepage
          • Latest
          • Login
          • Profile
          • Register
          • Reset Password
          • Trending
          • Users
          • Users List Item
          • 不只加密貨幣,談談那些你不知道的區塊鏈應用|動區新手村
          • 所有文章
          • 關於 BlockTempo

          © 2025 JNews - Premium WordPress news & magazine theme by Jegtheme.

          Welcome Back!

          Login to your account below

          Forgotten Password? Sign Up

          Create New Account!

          Fill the forms below to register

          All fields are required. Log In

          Retrieve your password

          Please enter your username or email address to reset your password.

          Log In

          Add New Playlist