Remix编译Vyper闪贷套利合约遇split相关未定义属性错误求助
Vyper闪贷套利合约编译报错:Cannot read properties of undefined (reading 'split')
我正在编写一个Vyper智能合约,实现从Aave获取闪贷,通过Uniswap完成兑换后再用Curve兑换,最终归还Aave的流程,以此练习Web3开发中的路由器、闪贷等概念。但在Remix中编译时出现以下错误:
Cannot read properties of undefined (reading 'split')
我的代码里并没有使用.split()方法,怀疑和路由器相关,但已经对照文档确认参数传递无误。错误没有提供行号,完全不知道从哪里开始调试,求帮忙解决。
合约代码
#pragma version ^0.3.3 """ @title Crypto Arbitrage Smart Contract using Uniswap and Curve with getting a flash loan from AAVE @license UNLICENSED @author Salmon46 @notice Vyper implementation of Crypto Arbitrage smart contract """ from vyper.interfaces import ERC20 # set constants to desired level MAX_PARAMS_LEN: constant(uint256) = 32 MAX_ASSETS_LEN: constant(uint256) = 32 #initialize resource variables POOL: constant(address) = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2 #aave pool UNISWAP_V3_ROUTER: constant(address) = 0xE592427A0AEce92De3Edee1F18E0157C05861564 #Uniswap v3 Router from "https://github.com/curvefi/curve-router-ng/blob/master/contracts/Router.vy" import CryptoPoolETH #Curve Router # token addresses USDC: constant(address) = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 WETH9: constant(address) = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 #initialize owner owner: immutable(address) @external def __init__(_owner: address): owner = _owner @external def flash_call( _amount: uint256, #Prolly like 1000 ): """ @notice Make flash loan call to pool @dev Uses raw_call, since uint16 is not supported in vyper @param _asset Address of asset to borrow @param _amount Amount of asset to borrow (raw) @param _params Arbitrary params to pass to the receiver @param _referral_code Optional Aave referral code """ _receiver_address: constant(address) = self _asset: constant(address) = USDC _params: Bytes[MAX_PARAMS_LEN] = "" #_referral_code: Bytes[2] = 0 raw_call( POOL, _abi_encode( _receiver_address, _asset, _amount, _params, #_referral_code, method_id=method_id("flashLoanSimple(address,address,uint256,bytes,uint16)") ) ) @public def swapWithUniswap(amountIn: uint256) -> uint256: #Approve Uniswap router to spend USDC ERC20(USDC).approve(UNISWAP_V3_ROUTER, amountIn) #initialize params uniswapPoolFee: constant(uint256) = 3000 amountOutMinimum: uint256 = 0 #REMEMBER TO CHANGE sqrtPriceLimitX96: uint256 = 0 receiver_address: constant(address) = self amountOut: uint256 = raw_call( UNISWAP_V3_ROUTER, _abi_encode( USDC, WETH9, uniswapPoolFee, receiver_address, block.timestamp, amountIn, amountOutMinimum, #This is amountOutMinimum...REMEBER TO CHANGE sqrtPriceLimitX96, method_id=method_id("exactInputSingle((address, address, uint24, address, uint256, uint256, uint256, uint160))") ), ) return amountOut @public def swapWithCurve(amount_In: uint256) -> uint256: #Approve Curve Router to spend Wrapped ether ERC20(WETH9).approve(CryptoPoolETH, amount_In) #initalize paramss _route: address[11] = [ '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', # initial token: wETH '0x7f86bf177dd4f3494b841a37e810a34dd56c829b', # pool1: TricryptoUSDC (USDC, wBTC, wETH) '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', # output token: USDC '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', ] _swap_params: uint256[5][5] = [ [2, 0, 1, 3, 3], #1st element is token index of WETH in the TricryptoUSDC pool. 2nd element is the token index of USDC in the same pool. 3rd element is the type of swap --just a standard token exchange--. 4th element is the type of pool --using a TriCrypto pool. 5th elemnt is how many coins are in the pool --3 coins. [0, 0, 0, 0, 0], #Only doing 1 swap so that's why these are all empty [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ] _expected: uint256 = 0 #Same thing as amountOutMinimum...ALSO REMEMBER TO CHANGE _pools: address[5] = [ '0x7f86bf177dd4f3494b841a37e810a34dd56c829b', #TricryptoUSDC pool address '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000' ] _receiver_address: constant(address) = self amount_Out: uint256 = CryptoPoolETH.exchange( _route, _swap_params, amount_In, _expected, _pools, #Empty for pools since we are only using 1 pool aka only need this parameter for swap type 3 _receiver_address ) return amount_owed @external def executeOperation( _asset: address, _amount: uint256, _premium: uint256, _initiator: address, _params: Bytes[MAX_PARAMS_LEN] ) -> bool: """ @notice Executes logic with borrowed asset and set approval @dev This method is called by the Aave Pool @param _asset Addresses of asset borrowed @param _amount Amount of asset borrowed (raw) @param _premium Premium owed for asset borrowed (raw) @param _initiator Address of the initiator of the flash loan @param _params Arbitrary params passed by the initiator @return True if execution success """ # conduct logic postUniValue = swapWithUniswap(_amount) finalAmount = swapWithCurve(postUniValue) # approve transfer back to pool amount_owed: uint256 = _amount + _premium ERC20(_asset).approve(POOL, amount_owed) return True
已尝试的调试策略
- 参数检查:对照官方文档修正了所有接口的参数传递错误;
- 代码格式化:按逻辑执行顺序重新调整了函数定义和整体代码结构。
但无论怎么操作,编译时都会出现同样的错误。
解决建议
- 替换远程导入为本地接口:Remix对Vyper的远程文件导入支持存在bug,直接把Curve Router的
CryptoPoolETH接口内容复制到本地合约中,不要使用from "url" import的方式。 - 修复变量名错误:
swapWithCurve函数最后return的amount_owed未定义,应改为amount_Out,这类语法错误可能触发编译器异常处理逻辑,导致出现无关的split错误。 - 检查ABI编码的method_id:Uniswap V3的
exactInputSingle方法接收结构体参数,确保method_id中的结构体字段顺序、类型和Uniswap官方定义完全一致,比如fee参数的类型是uint24,method_id里要严格匹配,不要用uint256。 - 匹配Vyper版本:确认Remix中选择的Vyper编译器版本是
0.3.x系列,与pragma声明的^0.3.3一致,避免版本不兼容导致的解析错误。 - 清理注释中的特殊符号:注释里的
--等符号可能干扰编译器的注释解析,建议替换为普通单行注释或调整格式。
内容的提问来源于stack exchange,提问作者Sudin Gautam
相关产品推荐
相关产品推荐

