//存储位置
//storage 存储(状态变量)
//memory 内存(局部变量)
//calldata 和memory类似 只能够用在输入的参数中 这样传递的时候不用定义多个memory来消耗gas
contract DataLocations{
struct MyStruct{
uint foo;
string text;
}
mapping (address => MyStruct) public myStructs;
function examples(uint[] calldata y,string calldata s) external returns(uint[] memory){
myStructs[msg.sender] = MyStruct({foo: 123 , text: "bar"});
MyStruct storage myStruct = myStructs[msg.sender];//像指针一样的传了地址 如果改这个变量里的值 链上的值就会发生改变
myStruct.text = "foo";
MyStruct memory readOnly = myStructs[msg.sender];//局部变量改了也不会保存到链上
readOnly.foo = 456;
_internal(y);
uint[] memory memArr = new uint[](3);
memArr[0] = 222;
return memArr;
}
function _internal(uint[] calldata y) private {
uint x = y[0];
}
}
简单存储
contract SimpleStorage{
string public text;
//输入相同参数的情况下 calldata比memory的gas消耗量要更小
function set(string calldata _text) external {
text = _text;
}
function get() external view returns (string memory){
return text;//把状态变量拷贝到内存中然后返回
}
}
待办列表案例
contract TodoList{
struct Todo{
string text;
bool completed;
}
Todo[] public todos;
function create(string calldata _text) external {
todos.push(Todo({
text: _text,
completed: false
}));
}
function updateText(uint _index,string calldata _text) external {
todos[_index].text = _text;
Todo storage todo = todos[_index];
todo.text = _text;
}
//如果需要改很多参数 用storage更节省gas 否则不需要
}
contract Event{
//事件是一种记录当前智能合约运行状态的方法 并不记录在状态变量中 而是体现在区块链浏览器上或者交易记录中
//通过事件可以查询改变过的状态
//声明事件 大写开头 事件报告的数据类型
event Log(string message, uint val);
event IndexedLog(address indexed sender,uint val);//indexed 关键字的意义在于提高事件日志的查询效率
//每个事件最多可以有三个 indexed 参数
function example() external {
//触发事件
emit Log("foo",123);
emit IndexedLog(msg.sender,789);
}//改变了链上事件的状态
event Message(address indexed _from , address indexed _to , string message);
function sendMessage(address _to, string calldata message) external {
emit Message(msg.sender, _to, message);
}//事件的存储更节约gas
}
//关键词 virtual 标记函数可被重写
//关键词 override 标记函数已被重写
contract A {//父合约
function foo() public pure virtual returns (string memory){
return "A";
}
function bar() public pure virtual returns (string memory){
return "A";
}
function baz() public pure returns (string memory){
return "A";
}
}
contract B is A{
function foo() public pure override returns (string memory){
return "B";
}
}
contract C is B{
function bar() public pure override returns(string memory){
return "C";
}
}
//继承父级合约构造函数 的两种方式
contract S {
string public name;
constructor(string memory _name){
name = _name;
}
}
contract T{
string public text;
constructor(string memory _text){
text = _text;
}
}
contract U is S("s") , T("t"){//在已知给定值的情况下
}
contract V is S,T{
constructor(string memory _name ,string memory _text) S(_name) T(_text){
}//赋值根据继承的顺序来 和构造函数后续修饰无关
}
//两种方式混合使用
contract VV is S("s"),T{
constructor(string memory _text) T(_text){
}
}
contract VO is S , T{
//构造函数初始化的顺序根据继承顺序来 基础的被继承合约放前面
constructor(string memory _name,string memory _text) S(_name) T(_text){
}
}
/*
E
/ \
F G
\ /
H
*/
contract E{
event Log(string message);
function foo() public virtual {
emit Log("E.foo");
}
function bar() public virtual {
emit Log("E.bar");
}
}
contract F is E{
function foo() public virtual override {
emit Log("F.foo");
//调用父级合约的两种方式
E.foo();
}
function bar() public virtual override {
emit Log("F.bar");
super.bar();
}
}
contract G is E{
function foo() public virtual override {
emit Log("G.foo");
//调用父级合约的两种方式
E.foo();
}
function bar() public virtual override {
emit Log("G.bar");
super.bar();
}
}
contract H is F, G{
function foo() public override (F, G){
F.foo();//指定父F
}
function bar() public override (F, G){
super.bar();//所有父
}
}
public 公开 合约内部和被继承的子合约中 以及外部可见
private 私有 合约内部可见
external 外部 仅在合约外部调用可见 内部不可见
internal 内部 合约的内部和被继承的子合约中可见
使用this可以访问外部函数 但是太消耗gas不建议使用
contract SimpleStorage{
string public text;
//输入相同参数的情况下 calldata比memory的gas消耗量要更小
function set(string calldata _text) external {
text = _text;
}
function get() external view returns (string memory){
return text;//把状态变量拷贝到内存中然后返回
}
}
//不可变量
contract Immutable{
// address public immutable owner = msg.sender;
address public immutable owner;
//常量需要一开始就赋值定值
//不可变量赋值一次就不可变了 使用这种方式更节省gas
//但是必须在定义的时候赋值 要么就在构造函数中赋值 不然就报错 部署合约的时候就必须得赋值
constructor(){
owner = msg.sender;
}
uint public x;
function foo() external {
require(msg.sender == owner);
x += 1;
}
//payable关键字表示可以接收以太坊主币 部署后红色按钮
contract Payable{
address payable public owner;
constructor(){
owner = payable (msg.sender); //需要转换成payable类型的
}
function deposit() external payable {
}
//显示当前余额
function getBalance() external view returns (uint){
return address(this).balance;
}
}
contract FallBack{
event Log(string func, address sender, uint value ,bytes data);
//回退函数有两种方式
fallback() external payable {
emit Log("fallback", msg.sender, msg.value, msg.data);
}
receive() external payable {
emit Log("receive", msg.sender, msg.value, "");
}
//fallback和receive的逻辑关系 看以下伪代码
// if(msg.data为空){
// if(receive()方法存在){
// 执行receive()方法
// }else{
// 执行fallback()方法
// }
// }else{
// 执行fallback()方法
// }
}
//三种方式发送ETH
//1.transfer 2300gas 失败会reverts
//2.send 2300gas 返回bool标记是否成功
//3.call all gas 返回bool和data
contract SendEther{
//存入主币的两种方式
constructor() payable {
}
receive() external payable {
}
function sendViaTransfer(address payable _to) external payable{
_to.transfer(123);
}
function sendViaSend(address payable _to) external payable {
bool sent = _to.send(123);
require(sent,"send failed");
}
function sendViaCall(address payable _to) external payable {
(bool success, ) = _to.call{value: 123}("");
require(success,"call failed");
}
}
contract EthReceiver{
event Log(uint amount ,uint gas);
receive() external payable {
emit Log(msg.value,gasleft());
}
}
//钱包合约
contract EtherWallet{
address payable public owner;
constructor(){
owner = payable (msg.sender);
}
receive() external payable { }//接受到主币的发送
function withdraw(uint _amount) external {
require(payable(msg.sender) == owner,"caller is not owner");
payable (msg.sender).transfer(_amount);
}
function getBalance() external view returns (uint){
return address(this).balance;
}
}
//调用其他合约
contract CallTestContract{
function setX1(address _test,uint _x) external {
//调用其他合约的方法的方式
TestContract(_test).setX(_x);//把另一个合约当做类型 然后传入地址
}
function setX2(TestContract _test,uint _x) external {
//调用其他合约的方法的方式
_test.setX(_x);//使用合约对象调用
}
function getX(address _test) external view returns (uint) {
uint x = TestContract(_test).getX();
return x;
}
function setXandSendEther(address _test,uint _x) external payable {
TestContract(_test).setXandReceiveEther{value: msg.value}(_x);//传递主币{value: msg.value}
}
function getXandValue(address _test) external view returns (uint,uint) {
(uint x,uint value) = TestContract(_test).getXandValue();
return (x,value);
}
}
//接口
interface ICounter {
//定义方法但不实现
function count() external view returns (uint);
function inc() external ;
}
contract CallInterface{
uint public count;
function examples (address _counter) external {
ICounter(_counter).inc();
count = ICounter(_counter).count();
}
}
//假如这个合约我们不清楚里面的内容 或者内容过多 就可以在其他地方先部署 然后通过接口方法来调用
contract Couter{
uint public count;
function inc() external {
count += 1;
}
function dec() external {
count -= 1;
}
}
//低级调用另一个合约
contract TestCall{
string public message;
uint public x;
function foo(string memory _message, uint _x) external payable returns (bool,uint){
message = _message;
x = _x;
return (true,999);
}
}
contract Call{
bytes public data;
function callFoo(address _test) external {
(bool success, bytes memory _data) = _test.call{value: 111, gas:5000}(
abi.encodeWithSignature(
"foo(string,uint256)", "call foo" ,123
)
);
require(success,"call failed");
data = _data;
}
}
//委托调用
contract TestDelegateCall{
uint public num;
address public sender;
uint public value;
function setVars(uint _num) external payable {
num = _num;
sender = msg.sender;
value = msg.value;
}
}
contract DelegateCall{
uint public num;
address public sender;
uint public value;
function setVars(address _test,uint _num) external payable {
//签名编码调用
// _test.delegatecall(
// abi.encodeWithSignature("setVars(uint256)", _num)
// );
(bool success , bytes memory data) =_test.delegatecall(
abi.encodeWithSelector(TestDelegateCall.setVars.selector, _num)
);
require(success,"delegatecall failed");
}
}
//两个局部变量需要一一对应 后续加可行
//工厂合约
contract Account{
address public bank;
address public owner;
constructor(address _owner) payable {
bank = msg.sender;
owner = _owner;
}
}
contract AccountFactory{
Account[] public accounts;
function createAccount(address _owner) external payable {
Account account = new Account{value: 111}(_owner);
accounts.push(account);
}
}
//库合约
library Math{//定义这个方法的时候 要么内部 要么公开 如果设成外部的话 内部就访问不了了
function max(uint x, uint y) internal pure returns (uint){
return x >= y ? x : y;
}
}
contract Test{
function testMax(uint x, uint y) external pure returns (uint){
return Math.max(x , y);
}
}
//数据查找
library ArrayLib {
function find(uint[] storage arr ,uint x) internal view returns (uint){
for (uint i = 0; i < arr.length ; i++) {
if(arr[i] == x){
return i;
}
}
revert("not found");
}
}
contract TestArray{
using ArrayLib for uint[];//用于为特定类型添加库函数
uint[] public arr = [3,2,1];
function testFind() external view returns (uint i){
// return ArrayLib.find(arr,2);
return arr.find(2);
}
}
//哈希运算
contract HashFunc{
function hash (string memory text,uint num ,address addr) external pure returns (bytes32){//hash值特定类型
//打包形式1 有点压缩
//keccak256(abi.encodePacked(text,num,addr)) //不会补0
// return keccak256(abi.encode(text,num,addr));//会补0
return keccak256(abi.encodePacked(text,num,addr));
//打包形式应该选一样的 不然哈希碰撞几率大
}
}
//验证签名
contract VerifySig{
function verify(address _signer, string memory _message, bytes memory _sig)
external pure returns (bool){
bytes32 messageHash = getMessageHash(_message);
bytes32 ethSingedMessageHash = getEthSignedMessageHash(messageHash);
return recover(ethsignedMessageHash,_sig) == _signer;
}
function getMessageHash(string memory _message) public pure returns (bytes32){
return keccak256(abi.encodePacked(_message));
}
function getEthSignedMessageHash(bytes32 _messageHash) public pure returns (bytes32){
return keccak256(abi.encodePacked(
"\x19Etherum Signed Message:\n32",
_messageHash
));
}
function recover(bytes32 _ethSignedMessageHash,bytes memory _sig)
public pure returns (address){
(bytes32 r,bytes32 s,uint8 v) = _split(_sig);
return ecrecover(_ethSignedMessageHash, v, r, s)
}
function _split(bytes memory _sig) internal pure
returns (bytes32 r,bytes32 s ,uint8 v){
}
}
//权限控制合约 多种角色身份
contract AccessControl{
event GrantRole(bytes32 indexed role, address indexed account);
event RevokeRole(bytes32 indexed role, address indexed account);
//角色->账户->布尔值
mapping (bytes32 => mapping (address => bool)) public roles;
//采用哈希值存储更合适
bytes32 private constant ADMIN = keccak256(abi.encodePacked("ADMIN"));
bytes32 private constant USER = keccak256(abi.encodePacked("USER"));
modifier onlyRole(bytes32 _role){
require(roles[_role][msg.sender],"not authorized");
_;
}
constructor(){
_grantRole(ADMIN, msg.sender);
}
//升级函数 给账户赋予权限
function _grantRole(bytes32 _role,address _account) internal{
roles[_role][_account] = true;
emit GrantRole(_role, _account);
}
function grantRole(bytes32 _role,address _account) external onlyRole(ADMIN) {
roles[_role][_account] = true;
emit GrantRole(_role, _account);
}
}
//自毁合约
//1.删除合约
//2.发送剩余所有eth
contract Kill{
constructor() payable {
}
function kill() external {
selfdestruct(payable(msg.sender));
}
function testCall() external pure returns(uint){
return 123;
}
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。