Solidity闪电贷实现方式与Move以及Rust闪电贷实现方式有何不同?

OKX欧易app

OKX欧易app

欧易交易所app是全球排名第一的虚拟货币交易所,注册领取6万元盲盒礼包!

APP下载   官网注册

作者:Beosin安全研究专家Sivan

闪电贷是一种无抵押借款的服务,由于其拥有无需抵押便能借出资金的特性,使得资金利用率大大提高。在常见的以太坊闪电贷中,是通过以太坊交易机制来保证可以进行无抵押借出资金,以太坊中一个交易可以包含很多步骤,如:借款、兑换、使用、还款等,所有的步骤相辅相成,若其中某一个或多个步骤出现错误,都将导致本次的整个交易被回滚。

随着区块链生态发展,出现了大量公链以及合约编程语言,例如:除了Solidity之外最常见的Move和Rust,这些合约编程语言有本质上的区别,框架与编程理念也有所不同,本篇文章我们来对比一下Solidity闪电贷实现方式与Move以及Rust闪电贷实现方式有何不同,同时可以初步了解一下各种语言的编程理念。

Solidity相关闪电贷:

Solidity的闪电贷是基于Solidity支持动态调用这一特性来设计的,何为动态调用,也就是solidity支持在调用一个函数的过程中,动态传入需要调用的地址,如下例代码。每次调用都可以传入不同的地址,根据这个特点,便出现了solidity闪电贷的实现逻辑。

functioncallfun(addressaddr)public{addr.call();}

如下代码,将闪电贷抽象成了3个核心功能,

1、首先直接将资金发送给调用者;

2、再调用调用者合约,从而让调用者使用这些资金;

3、调用者使用结束,检查是否归还资金以及手续费,如果检查失败则回滚交易。(此处也可以直接使用transferfrom函数将调用则资金转移回来)

functionflashloan(uintamount,addressto){transfer(to,amount);//发送资金给调用者to.call();//调用调用者的合约函数check();//检查是否归还资金}

如下图,为Solidity语言中闪电贷的实现流程:

Solidity闪电贷实现方式与Move以及Rust闪电贷实现方式有何不同?

下列代码为真实项目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 能力详情:

https://move-book.com/advanced-topics/types-with-abilities.html

因此在move语言中的闪电贷实现,巧妙地利用了这种模式,将闪贷和还款操作抽象为两个函数进行处理,中间产生借贷资源记录借贷情况,该资源并没任何能力,只能够在还款函数中通过解包的方式将借贷资源给消耗掉,因此借贷操作必须和还款操作绑定在同一个操作中,否则闪电贷交易就会失败。

如下图,为move语言中闪电贷的实现流程。

Solidity闪电贷实现方式与Move以及Rust闪电贷实现方式有何不同?

如下代码,loan与repay两个函数相结合便可以实现闪电贷。需要使用闪电贷服务的用户,先调用loan函数申请借款。函数会首先判断是否有足够的资金提供借款,随后将资金发送给调用者,计算好费用后,创建一个没有任何能力的资源”receipt ”并返回给调用者。调用者在自己的合约中使用借贷的资金,最后需要将”receipt”返还到repay函数,并且附带归还的资金。在repay函数中,首先将”receipt”资源解构,以确保交易成功执行,随后判断用户归还资金是否与之前计算好的资金数量相同,最后完成整个交易。

代码示例:

structReceipt<phantomT>{flash_lender_id:ID,repay_amount:u64}publicfunloan<T>(self:&mutFlashLender<T>,amount:u64,ctx:&mutTxContext):(Coin<T>,Receipt<T>){letto_lend=&mutself.to_lend;assert!(balance::value(to_lend)>=amount,ELoanTooLarge);letloan=coin::take(to_lend,amount,ctx);letrepay_amount=amount+self.fee;letreceipt=Receipt{flash_lender_id:object::id(self),repay_amount};(loan,receipt)}publicfunrepay<T>(self:&mutFlashLender<T>,payment:Coin<T>,receipt:Receipt<T>){letReceipt{flash_lender_id,repay_amount}=receipt;assert!(object::id(self)==flash_lender_id,ERepayToWrongLender);assert!(coin::value(&payment)==repay_amount,EInvalidRepaymentAmount);coin::put(&mutself.to_lend,payment)}

Rust相关闪电贷:

Rust由于其提供内存安全、并发安全和零成本抽象等特性。也被用在了区块链智能合约语言开发中,接下来我们以Solana智能合约(Program)为例讲解使用Rust开发实现的闪电贷。

Solana VM 亦将数据和执行代码进行了分离,使得一份执行代码可以处理多份数据副本,但与Move不同的是,数组账户是通过程序派生的方式完成的,并且没有类似于Move特性的限制。因此Solana Rust不能够使用Move的方式实现闪电贷,并且Solana Rust动态调用指令(等同于理解为合约的函数)递归深度限制为4,使用Solidity动态调用的方式同样不可取。但在Solana中每个指令(instruction)调用在交易中是原子类型的,因此在一笔交易中可以在一个指令中检查是否存在另一个指令。而Solana中的闪电贷依赖此了特性,Solana闪电贷在闪贷的指令中将检查闪电贷交易中是否存在还款的指令,并检查还款的数量是否正确。

如下图,为Rust语言中闪电贷的实现流程:

Solidity闪电贷实现方式与Move以及Rust闪电贷实现方式有何不同?

代码示例:

pub fn borrow(ctx: Context<Borrow>, 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 tokenspub fn repay(ctx: Context<Repay>, 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每个指令都是原子类型,并且支持指令自省,因此使用指令自省的方式实现闪电贷是较好的方式。

本站所有软件信息均由用户上传发布,版权归原著所有。如有侵权/违规内容,敬请来信告知邮箱:764327034@qq.com,我们将及时撤销! 转载请注明出处:https://czxurui.com/zx/92655.html

打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年10月26日
下一篇 2023年10月26日

相关推荐

  • CELL是什么币子,闪电比特币是什么

    一、SK是一种什么币啊是化妆品sk系列到台湾的官方网站看吧!1.世界知名化妆品品牌中英对照2.护肤化妆术语3.化妆品权威选购指南4.各品牌化妆品的权威推荐与不推荐1.世界知名化妆品品牌中英对照ANNA SUI安娜“苏AVON雅芳avene雅漾Biotherm碧欧泉Borghese贝佳斯Chanel香乃尔Chri

    2024-12-20 04:00:01
    7 0
  • 闪电网络代币是什么,闪电网络代币叫什么

    一、闪电网络代币叫什么闪电网络代币莱特币,英文名为Lightning Labs。莱特币是比特币的直接竞争对手之一,莱特币的交易费是非常低的。一旦比特币成为闪电网络的主流货币,莱特币的交易费用优势将成为劣势。2017年11月Lightning Labs宣布,他们将通过跨链进行原子代币交换的首

    2024-12-09 04:00:01
    17 0
  • 闪电比特币发行多少,比特币的闪电节点有多少个

    一、比特币的闪电节点有多少个据1ML数据,当前比特币闪电网络节点数量达到18061个,过去30天内增加7.30%;通道数量为40065个,过去30天内增加5.9%;网络容量达到1154个BTC,过去30天内增加6%。btc链乔教育在线旗下学硕创新区块链技术工作站是中国教育部学校规划建设发展中心开

    2024-11-29 16:30:01
    43 0
  • 闪电网络标志是什么牌子,闪电卫衣什么牌子

    一、闪电卫衣什么牌子闪电卫衣的品牌为闪电潮牌,GENANX。闪电潮牌的LOGO是品牌卡通形象“闪电君”的黑白头像,双眼中透露着果断。整体LOGO呈现出非黑即白的强烈对比,本质是在表达一种“没有灰色地带,没有差不多”的态度。GENANX闪电潮牌,为年轻人提供潮流货。品牌被打上标

    2024-11-24 00:00:01
    19 0
  • 闪电网络发行的币叫什么,闪电网络代币叫什么

    一、比特币和闪电比特币有什么区别与BCH和BSV等分叉币相比,闪电比特币LBTC同样是源自于比特币,其诞生的初衷也是为了解决比特币本身所存在的一些不足和缺陷,但是LBTC最大的不同在于采用了DPoS共识机制,而不是PoW共识机制,其所带来的最显著的好处有以下几点:一是大大提高

    2024-11-17 18:00:01
    19 0
  • 闪电网络图标是什么牌子,闪电网络代币叫什么

    一、...的95后年轻人走红网络,闪电在他们的镜头下是什么样的一段关于闪电的视频在网上迅速走红,这则视频由用户名叫亿点点不一样的网友发布的,根据相关媒体的报道,这则关于闪电的视频是由一群95后年轻人拍摄的,他们都属于一个名叫影视飓风的团队。在他们所拍摄的视频里闪电

    2024-11-15 23:00:02
    25 0

发表回复

8206
验证码

评论列表(0条)

    暂无评论

ok交易所
已有100万用户加入ok交易所

立即下载