我们知道在Java里接口是特殊的抽象类,限制多于抽象类,但随着Java版本的更新,Java中的接口是越来越趋于抽象类了(这样说,可能有点不妥,因为接口本就是特殊的抽象类,只是接口中不能有方法具体实现,而抽象类还是可以有的!然而随着Java版本的
接口(interface)
我们知道在Java里接口是特殊的抽象类,限制多于抽象类,但随着Java版本的更新,Java中的接口是越来越趋于抽象类了(这样说,可能有点不妥,因为接口本就是特殊的抽象类,只是接口中不能有方法具体实现,而抽象类还是可以有的!然而随着Java版本的推移,Java 接口中可以有方法实现了 )。
虽然在 Solidity 中的接口跟抽象合约很类似,但接口却不能像抽象合约那样,可以有方法体函数实现。
接口基本上仅限于合约 ABI 可以表示的内容,并且 ABI 和接口之间的转换不应该丢失任何信息。
Solidity 中的接口是不能有函数实现的,且还有以下节点约束:
- 1、不能继承除了接口外的其他合约
- 2、接口中的所有
函数签名都必须是external。 - 3、无法声明构造函数。
- 4、不能定义
状态变量。 - 5、继承接口的合约必须实现接口中声明的函数功能。
就目前来看,接口有这些限制,但在不久的将来,有可能解除某些限制(本次使用的是Solidity ^0.8.0)。
使用关键字interface来声明一个接口。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
interface MyToken {
enum TokenType { Fungible, NonFungible }
struct Coin { string obverse; string reverse; }
function transfer(address recipient, uint amount) external;
}


// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
interface MyToken {
enum TokenType { Fungible, NonFungible }
struct Coin { string obverse; string reverse; }
//接口中所有 函数签名 隐式标记为 virtual
function transfer(address recipient, uint amount) external;
}
interface MyCoin {
function transfer(address recipient, uint amount) external;
}
//合约实现多接口
contract MyTest is MyToken,MyCoin {
function transfer(address recipient, uint amount) override(MyToken,MyCoin) external{
}
}
//接口继承多接口
interface TestI is MyToken,MyCoin {
function transfer(address recipient, uint amount) override(MyToken,MyCoin) external;
}
虽然接口有这么多的限制,不能像抽象合约的那样可以有实现体,但接口在 Solidity 中却很重要。它定义了合约的骨架,如合约实现了某些接口(ERC20 或 ERC721),其他Dapp就可以与我们编写的智能合约进行交互。
我们以IERC721为例,它定义了3个后续将会讲到的事件(event)和9个函数(function),所有ERC721标准的NFT都实现了这些函数。
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
IERC721事件
IERC721包含3个事件,其中Transfer和Approval事件在ERC20中也有。
Transfer事件:在转账时被释放,记录代币的发出地址from,接收地址to和tokenid。Approval事件:在授权时释放,记录授权地址owner,被授权地址approved和tokenid。ApprovalForAll事件:在批量授权时释放,记录批量授权的发出地址owner,被授权地址operator和授权与否的approved。
IERC721函数
balanceOf:返回某地址的NFT持有量balance。ownerOf:返回某tokenId的主人owner。transferFrom:普通转账,参数为转出地址from,接收地址to和tokenId。safeTransferFrom:安全转账(如果接收方是合约地址,会要求实现ERC721Receiver接口)。参数为转出地址from,接收地址to和tokenId。approve:授权另一个地址使用你的NFT。参数为被授权地址approve和tokenId。getApproved:查询tokenId被批准给了哪个地址。setApprovalForAll:将自己持有的该系列NFT批量授权给某个地址operator。isApprovedForAll:查询某地址的NFT是否批量授权给了另一个operator地址。safeTransferFrom:安全转账的重载函数,参数里面包含了data。
使用接口
假使我们知道一个合约实现了ERC721接口的话,我们不必去关心它的具体实现功能,却可以与它进行交互。
不知道您有没有玩过加密猫(CryptoKitty ),这是一款风靡全球的区块链游戏()链游),而它便是实现了ERC721接口。
我可以使用IERC721接口来查看加密猫(CryptoKitty)中的余额。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
//导入 IERC721 接口
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract ShowKittyAmount {
// 利用 CryptoKitty 合约地址创建接口合约变量(ETH主网)
IERC721 kitty = IERC721(0xba52c75764d6F594735dc735Be7F1830CDf58dDf);
// 通过接口调用 CryptoKitty 的balanceOf()查询持仓量
function balanceOfKitty(address owner) external view returns (uint256 balance){
return kitty.balanceOf(owner);
}
// 通过接口调用 CryptoKitty 的safeTransferFrom()安全转账
function safeTransferFromKitty(address from, address to, uint256 tokenId) external{
kitty.safeTransferFrom(from, to, tokenId);
}
}

不过在部署时,要选择以太坊主网,否则查询不出结果!


2022-12-17 14:59:55 +0800 +0800
2022-12-16 20:15:16 +0800 +0800
2022-12-14 22:21:38 +0800 +0800
2022-12-14 09:31:48 +0800 +0800
2022-12-12 22:08:10 +0800 +0800