Solidity合约编译错误排查:calldata与未声明标识符问题
解决Remix编译Solidity合约的两类错误:数据位置缺失与未声明标识符
一、初始错误分析与修正
你遇到的第一个编译错误是因为Solidity 0.5.0及以上版本要求外部函数的引用类型参数(如string)必须显式指定数据位置,外部函数的引用类型只能用calldata(因为外部函数的参数默认存储在调用数据中)。你把function updateTokenName(string _name) external onlyOwner修改为function updateTokenName(string calldata _name) external onlyOwner是完全正确的,后续的新错误是合约本身存在未定义变量的问题,和这次修改无关。
二、新错误:未声明标识符的原因与修复
后续出现的Undeclared identifier错误,是因为合约中使用了多个未在状态变量区域声明的变量,同时还有函数重复定义的问题,具体修复如下:
1. 补充缺失的状态变量声明
在合约开头的状态变量区域(address public owner;之后)添加以下三个变量:
mapping(address => mapping(address => uint256)) public allowed; // 存储地址间的授权额度 bool public paused; // 标记合约是否处于暂停状态 string public tokenName; // 存储代币名称
allowed:用于实现ERC20标准的授权转账逻辑,你在approve、allowance、transferFrom等函数中都用到了这个映射,但之前没有声明。paused:pause和unpause函数用来切换合约状态,但变量未定义。tokenName:updateTokenName函数要更新这个变量,但之前没有声明。
2. 修复重复定义的transferFrom函数
合约中存在两个参数完全相同的transferFrom函数,Solidity不允许这种重载(重载要求参数数量或类型不同)。保留带授权校验的版本,删除无授权校验的那个,修正后的transferFrom函数如下:
function transferFrom(address _from, address _to, uint256 _tokens) external { require(_tokens > 0 && tokenBalanceOf[_from] >= _tokens && allowed[_from][msg.sender] >= _tokens); tokenBalanceOf[_from] -= _tokens; tokenBalanceOf[_to] += _tokens; allowed[_from][msg.sender] -= _tokens; emit Transfer(_from, _to, _tokens); }
3. 修复burnFrom函数的参数错误
burnFrom函数触发Burn事件时使用了未定义的_to参数,修改事件触发语句为代币销毁的标准写法(转到零地址):
function burnFrom(address _from, uint256 _tokens) external { require(_tokens > 0 && tokenBalanceOf[_from] >= _tokens && allowed[_from][msg.sender] >= _tokens); tokenBalanceOf[_from] -= _tokens; allowed[_from][msg.sender] -= _tokens; emit Burn(_from, address(0), _tokens); // 修正为零地址,符合代币销毁逻辑 }
三、完整修正后的合约代码
pragma solidity ^0.5.0; contract FractionalizedAssets { address public owner; // 合约创建者 mapping(address => uint256) public tokenBalanceOf; // 地址与代币余额的映射 mapping(address => mapping(address => uint256)) public allowed; // 存储地址间的授权额度 bool public paused; // 标记合约是否处于暂停状态 string public tokenName; // 存储代币名称 constructor() public { owner = msg.sender; } function mint(uint256 _amount, address _to) external onlyOwner { require(_amount > 0); tokenBalanceOf[_to] += _amount; // 增加指定用户的代币余额 } function transfer(address _from, address _to, uint256 _tokens) external { // 允许用户之间交易代币 require(tokenBalanceOf[_from] >= _tokens && _tokens > 0); // 确保发送者有足够代币 tokenBalanceOf[_from] -= _tokens; // 从发送者账户扣除代币 tokenBalanceOf[_to] += _tokens; // 给接收者账户增加代币 emit Transfer(_from, _to, _tokens); // 触发转账事件 } event Transfer(address indexed from, address indexed to, uint256 value); modifier onlyOwner() { require(msg.sender == owner); _; } function burn(uint256 _amount, address _from) external onlyOwner { require(_amount > 0); tokenBalanceOf[_from] -= _amount; // 减少指定用户的代币余额 } function totalSupply() public view returns (uint256) { return address(this).balance; // 返回流通中的代币总供应量 } function balanceOf(address _owner) public view returns (uint256) { return tokenBalanceOf[_owner]; // 返回指定地址的代币余额 } function approve(address _spender, uint256 _tokens) external { allowed[msg.sender][_spender] = _tokens; // 允许授权方多次从调用者账户提取指定额度内的代币 } function allowance(address _owner, address _spender) public view returns (uint256) { return allowed[_owner][_spender]; // 返回授权方仍可从所有者账户提取的剩余代币数量 } function transferFrom(address _from, address _to, uint256 _tokens) external { require(_tokens > 0 && tokenBalanceOf[_from] >= _tokens && allowed[_from][msg.sender] >= _tokens); // 确保发送者有足够代币且授权额度充足 tokenBalanceOf[_from] -= _tokens; // 从发送者账户扣除代币 tokenBalanceOf[_to] += _tokens; // 给接收者账户增加代币 allowed[_from][msg.sender] -= _tokens; // 减少授权方剩余可提取额度 emit Transfer(_from, _to, _tokens); // 触发转账事件 } function increaseApproval(address _spender, uint256 _addedValue) external { allowed[msg.sender][_spender] += _addedValue; // 增加授权方的可提取额度 } function decreaseApproval(address _spender, uint256 _subtractedValue) external { allowed[msg.sender][_spender] -= _subtractedValue; // 减少授权方的可提取额度 } function burnFrom(address _from, uint256 _tokens) external { require(_tokens > 0 && tokenBalanceOf[_from] >= _tokens && allowed[_from][msg.sender] >= _tokens); // 确保发送者有足够代币且授权额度充足 tokenBalanceOf[_from] -= _tokens; // 从发送者账户扣除代币 allowed[_from][msg.sender] -= _tokens; // 减少授权方剩余可提取额度 emit Burn(_from, address(0), _tokens); // 触发销毁事件 } event Burn(address indexed from, address indexed to, uint256 value); function burnAll(address _from) external onlyOwner { uint256 balance = tokenBalanceOf[_from]; // 获取用户当前代币余额 require(balance > 0); // 确保用户有可销毁的代币 tokenBalanceOf[_from] = 0; // 将用户代币余额设为0 emit Burn(_from, address(0), balance); // 触发销毁事件 } function pause() external onlyOwner { paused = true; // 将合约设为暂停状态 emit Pause(); // 触发暂停事件 } function unpause() external onlyOwner { paused = false; // 将合约设为非暂停状态 } event Pause(); function renounceOwnership() external onlyOwner { emit OwnershipRenounced(owner); // 触发放弃所有权事件 owner = address(0); // 将合约所有者设为零地址 } event OwnershipRenounced(address indexed previousOwner); function transferOwnership(address _newOwner) external onlyOwner { require(_newOwner != address(0)); // 确保新所有者不是零地址 emit OwnershipTransferred(owner, _newOwner); // 触发所有权转移事件 owner = _newOwner; // 将合约所有者设为新地址 } event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function reclaimEther() external onlyOwner { owner.transfer(address(this).balance); // 将合约中所有ETH转移给所有者 emit ReclaimEther(); // 触发回收ETH事件 } event ReclaimEther(); function destroy() external onlyOwner { selfdestruct(owner); // 销毁合约并将所有ETH转移给所有者 emit Destroy(); // 触发销毁事件 } event Destroy(); function updateOwner(address _newOwner) external onlyOwner { require(_newOwner != address(0)); // 确保新所有者不是零地址 emit OwnershipTransferred(owner, _newOwner); // 触发所有权转移事件 owner = _newOwner; // 将合约所有者设为新地址 } function updateTokenName(string calldata _name) external onlyOwner { tokenName = _name; // 更新代币名称 emit TokenNameUpdated(_name); // 触发代币名称更新事件 } event TokenNameUpdated(string indexed newTokenName); }
内容的提问来源于stack exchange,提问作者Let Me Tink About It
相关产品推荐
相关产品推荐

