作者:阿三 博客:Nockygo 公众号:阿三爱吃瓜
持续不断记录、整理、分享,让自己和他人一起成长!😊
modifier作用 其实就是可以作为校验器来处理,比如限制权限,只能在合约部署的人才可以使用,其他账号只能做其他处理,或者金额要超过多少。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 pragma solidity >=0.7 .0 <0.9 .0 ; contract ExampleModifier { address public owner; uint256 public account; constructor ( ){ owner = msg.sender ; account = 0 ; } modifier onlyOwner (uint256 _account ){ require (msg.sender == owner,"Only Owner" ); require (_account>100 ,"Valid 100" ); _; } function updateAccount (uint256 _account ) public onlyOwner (_account ){ account = _account; } }
event 作用 其实就是event emit 提交 写log日志
1 2 3 4 5 6 7 8 9 10 11 12 pragma solidity >=0.7 .0 <0.9 .0 ; contract ExampleEvent { event Deposit (address _from,string _name,uint256 _value); function deposit (string memory _name ) public payable { emit Deposit (msg.sender , _name, msg.value ); } }
view pure区别 pure 不允许访问状态变量 也不允许更改 view 允许访问 不允许更改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 pragma solidity >=0.7 .0 <0.9 .0 ; contract ExampleView { uint public age; function increaseAge ( ) public { age ++; } function getAgeWithView ( ) public view returns (uint ){ return age; } function getAgeWithPure (uint _age ) public pure returns (uint){ _age ++; return _age; } }
public private internal external 用法 external 只能从外部访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 pragma solidity >=0.7 .0 <0.9 .0 ; contract Salary { uint public data; function getData ( ) external view returns (uint) { return data; } function setData (uint _data ) external { data = _data; } } contract Employee { Salary salary; constructor ( ){ salary = new Salary (); } function getSalary ( ) external view returns (uint) { return salary.getData (); } function setSalary (uint _data ) external { salary.setData (_data); } }
address 有哪些
合约地址,创建不会改变
owner地址
与合约打交道的人的地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 pragma solidity >=0.7 .0 <0.9 .0 ; contract ExampleAddress { address ownerAddress; constructor ( ) { ownerAddress = msg.sender ; } function getContractAddress ( ) external view returns (address){ return address (this ); } function getSenderAddress ( ) external view returns (address){ return address (msg.sender ); } function getOwnerAddress ( ) external view returns (address){ return address (ownerAddress); } function getBalance ( ) external view returns (uint,uint,uint){ uint contractBalance = address (this ).balance ; uint senderBalance = msg.sender .balance ; uint ownerBalance = ownerAddress.balance ; return (contractBalance,senderBalance,ownerBalance); } }
address支付方法 接收和转账代币参数和return 必须追加payable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 pragma solidity >=0.7 .0 <0.9 .0 ; contract ExampleAddressFunction { function send (address payable _to ) public payable { bool isSend = _to.send (msg.value ); require (isSend,"Send fail" ); } function transfer (address payable _to ) public payable { _to.transfer (msg.value ); } function call (address payable _to ) public payable { (bool isSend,) = _to.call {value :msg.value ,gas :5000 }("" ); require (isSend,"Send fail" ); } }
call 方法 支付+调用智能合约 正常call 方法后面不加参数,会进入到receive方法, 如果存在参数,就会进入fallback 方法,同时返回的log日志中data是空的, 如果想要data中数据不为空,那就重新写一个方法,使用
1 2 3 4 5 6 7 function foo (string memory _message,uint _y ) public payable returns (uint){ emit Received (msg.sender , msg.value , _message); return _y; } abi.encodeWithSignature ("foo(string,uint256)" , "call foo" ,_y)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 pragma solidity >=0.7 .0 <0.9 .0 ; contract Receiver { event Received (address caller,uint amount,string message); receive () external payable { emit Received (msg.sender ,msg.value ,"Receive was called" ); } fallback () external payable { emit Received (msg.sender ,msg.value ,"Fallback was called" ); } function foo (string memory _message,uint _y ) public payable returns (uint){ emit Received (msg.sender , msg.value , _message); return _y; } function getAddress ( ) public view returns (address ){ return address (this ); } function getBalance ( ) public view returns (uint) { return address (this ).balance ; } } contract Caller { Receiver receiver; constructor ( ){ receiver = new Receiver (); } event Response (bool success,bytes data); function testCall (address payable _addr,uint _y ) public payable { (bool success,bytes memory data) = _addr.call {value :msg.value }( abi.encodeWithSignature ("foo(string,uint256)" , "call foo" ,_y) ); emit Response (success, data); } function getAddress ( ) public view returns (address){ return receiver.getAddress (); } function getBalance ( ) public view returns (uint) { return receiver.getBalance (); } }
constant 和Immutable区别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 pragma solidity >=0.7 .0 <0.9 .0 ; contract ConstantImmutable { string constant name = "Biden" ; uint immutable age; constructor ( ) { age = 100 ; } function getName ( ) public pure returns (string memory){ return name; } function getAge ( ) public view returns (uint) { return age; } }
mapping 的应用场景 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pragma solidity >=0.7 .0 <0.9 .0 ; contract MappingExample { mapping (address => uint) account; function get (address _address ) public view returns (uint){ return account[_address]; } function set (address _address,uint _balance ) public { account[_address] = _balance; } function remove (address _address ) public { delete account[_address]; } }
提到了mapping嵌套,具体还得再查下,但是mapping嵌套我理解上是二维数组类型的。
ERC20代币的介绍 使用openZeppelin 实现
数组应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 pragma solidity >=0.7 .0 <0.9 .0 ; contract ArrayExample { uint[] iArray; uint[] iArray2 = [1 ,2 ,3 ]; uint[3 ] iArray3; function getArray ( ) public view returns (uint[] memory){ return iArray2; } function getArrayByIndex (uint _i ) public view returns (uint) { return iArray2[_i]; } function getLength ( ) public view returns (uint){ return iArray3.length ; } function push (uint _i ) public { iArray2.push (_i); } function pop ( ) public { iArray2.pop (); } function deleteByIndex (uint _i ) public { delete iArray2[_i]; } }
imort引入文件应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pragma solidity >=0.7 .0 <0.9 .0 ; import "./13_import_1.sol" ;contract ImportExample2 { ImportExample importExample = new ImportExample (); function getAge ( ) public view returns (uint) { return importExample.age (); } function getName ( ) public view returns (string memory){ return importExample.getName (); } }
创建最简单DEX,进行ERC20交易 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 pragma solidity ^0.8 .2 ; library SafeMath { function sub (uint256 a,uint256 b ) internal pure returns (uint256){ assert (b%3C=a); return a-b; } function add (uint256 a,uint256 b ) internal pure returns (uint256){ uint256 c = a+b; assert (c%3E=a); return c; } } interface IERC20 { function getAddress ( ) external view returns (address); function totalSupply ( ) external view returns (uint256); function balanceOf (address account ) external view returns (uint256); function allowance (address owner,address spender ) external view returns (uint256); function transfer (address recipient,uint256 amount ) external returns (bool); function approve (address owner,address spender,uint256 amount ) external returns (bool); function transferFrom (address sender,address recipient,uint256 amount ) external returns (bool); event Transfer (address indexed from ,address indexed to,uint256 value); event Approval (address indexed owner,address indexed spender,uint256 value); } contract ERC20Basic is IERC20 { string public constant name = "ERC20-ThinkChain" ; string public constant symbol = "ERC-TKC" ; uint8 public constant decimals = 18 ; mapping (address => uint256) balances; mapping (address =>mapping (address => uint256)) allowed; uint256 totalSupply_ = 10 ether; using SafeMath for uint256; constructor ( ) { balances[msg.sender ] = totalSupply_; } function getAddress ( ) public override view returns (address){ return address (this ); } function totalSupply ( ) public override view returns (uint256){ return totalSupply_; } function balanceOf (address tokenOwner ) public override view returns (uint256) { return balances[tokenOwner]; } function transfer (address receiver,uint256 numTokens ) public override returns (bool){ require (numTokens <= balances[msg.sender ]); balances[msg.sender ] = balances[msg.sender ].sub (numTokens); balances[receiver] = balances[receiver].add (numTokens); emit Transfer (msg.sender ,receiver,numTokens); return true ; } function approve (address owner,address delegate,uint256 numTokens ) public override returns (bool){ allowed[owner][delegate] = numTokens; emit Approval (owner, delegate, numTokens); return true ; } function allowance (address owner,address delegate ) public override view returns (uint){ return allowed[owner][delegate]; } function transferFrom (address owner,address buyer,uint256 numTokens ) public override returns (bool){ require (numTokens<=balances[owner]); require (numTokens<=allowed[owner][msg.sender ]); balances[owner] = balances[owner].sub (numTokens); allowed[owner][buyer] = allowed[owner][buyer].sub (numTokens); emit Transfer (owner, buyer, numTokens); return true ; } } contract DEX { event Bought (uint256 amount); event Sold (uint256 amount); IERC20 public token; constructor ( ){ token = new ERC20Basic (); } function buy ( ) payable public { uint256 amountTobuy = msg.value ; uint256 dexBalance = token.balanceOf (address (this )); require (amountTobuy>0 ,"You need to send some Ether" ); require (amountTobuy<=dexBalance,"Not enough tokens in the reserve" ); token.transfer (msg.sender , amountTobuy); emit Bought (amountTobuy); } function sell (uint256 amount ) public { require (amount>0 ,"You need to sell at least some tokens" ); uint256 allowance = token.allowance (msg.sender , address (this )); require (allowance>=amount,"Check the token allowance" ); token.transferFrom (msg.sender , address (this ), amount); emit Sold (amount); } function getDexBalance ( ) public view returns (uint256) { return token.balanceOf (address (this )); } function getOwnerBalance ( ) public view returns (uint256) { return token.balanceOf (msg.sender ); } }
openzeppelin 合约 铸币合约
1 2 3 4 5 6 7 8 9 10 pragma solidity >=0.7 .0 <0.9 .0 ; import "@openzeppelin/contracts/token/ERC20/ERC20.sol" ;contract ThinkingChainToken is ERC20 { constructor ( ) ERC20 ("ThinkingChain" ,"TKC" ) { _mint (msg.sender , 1000 * 10 ** decimals ()); } }
接受代币的合约
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 pragma solidity >=0.7 .0 <0.9 .0 ; import "@openzeppelin/contracts/token/ERC20/IERC20.sol" ;contract ReciveTokenContract { IERC20 myToken; constructor (address _tokenAddress ) { myToken = IERC20 (_tokenAddress); } function transferFrom (uint _amount ) public { myToken.transferFrom (msg.sender ,address (this ),_amount); } function getBalance (address _address ) public view returns (uint ) { return myToken.balanceOf (_address); } }
interface 接口应用 先部署Employee 合约 再部署company合约
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 pragma solidity >=0.7 .0 <0.9 .0 ; interface IEmployee { function setName (string memory _name ) external ; function getName ( ) external view returns (string memory); } contract Employee is IEmployee { string private name; function setName (string memory _name ) public override { name = _name; } function getName ( ) public override view returns (string memory){ return name; } } contract Company { IEmployee employee; constructor (address _address ) { employee = IEmployee (_address); } function setName (string memory _name ) public { employee.setName (_name); } function getName ( ) public view returns (string memory){ return employee.getName (); } }
Library应用 使用类库的时候是_a.add(_b) 不是用safemath.add(_a,_b)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 pragma solidity >=0.7 .0 <0.9 .0 ; library SafeMath { function mul (uint256 a, uint256 b ) internal pure returns (uint256) { if (a == 0 ) { return 0 ; } uint256 c = a * b; require (c / a == b, "SafeMath: multiplication overflow" ); return c; } function div (uint256 a, uint256 b ) internal pure returns (uint256) { require (b > 0 , "SafeMath: division by zero" ); uint256 c = a / b; return c; } function sub (uint256 a, uint256 b ) public pure returns (uint256) { require (b <= a, "SafeMath: subtraction overflow" ); uint256 c = a - b; return c; } function add (uint256 a, uint256 b ) public pure returns (uint256) { uint256 c = a + b; require (c >= a, "SafeMath: addition overflow" ); return c; } function mod (uint256 a, uint256 b ) internal pure returns (uint256) { require (b != 0 , "SafeMath: modulo by zero" ); return a % b; } } contract Example { using SafeMath for uint256; function doAdd (uint256 _a,uint256 _b ) public pure returns (uint256 ){ return _a.add (_b); } function doSub (uint256 _a,uint256 _b ) public pure returns (uint256 ){ return _a.sub (_b); } function doAddMore (uint256 _a,uint256 _b,uint256 _c ) public pure returns (uint256) { return _a.addMore (_b,_c);} }
代理合约 用于智能合约的升级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pragma solidity >=0.7 .0 <0.9 .0 ; contract Logic { uint private number ; function setNumber (uint _number ) public { number = _number+1 ; } function getNumber ( ) public view returns (uint){ return number ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pragma solidity >=0.7 .0 <0.9 .0 ; contract Logic2 { uint private number ; function setNumber (uint _number ) public { number = _number+2 ; } function getNumber ( ) public view returns (uint){ return number ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 pragma solidity >=0.7 .0 <0.9 .0 ; interface ILogic { function setNumber (uint _number ) external ; function getNumber ( ) external view returns (uint); } contract Proxy { ILogic public logic; function setLogicAddress (address _logicAddress ) public { logic = ILogic (_logicAddress); } function getLogicAddress ( ) public view returns (address){ return address (logic); } function setNumber (uint _number ) public { logic.setNumber (_number); } function getNumber ( ) public view returns (uint){ return logic.getNumber (); } }
多态继承 当有覆写父类相同的方法时候,父类加virtual 子类加overwrite
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 pragma solidity >=0.7 .0 <0.9 .0 ; contract A { function getName ( ) public pure virtual returns (string memory) { return "A" ; } } contract B is A { function getAName ( ) public pure returns (string memory){ return super .getName (); } function getName ( ) public pure virtual override returns (string memory) { return "B" ; } } contract C is A { function getCName ( ) public pure returns (string memory){ return super .getName (); } function getName ( ) public pure virtual override returns (string memory) { return "C" ; } } contract BC is B,C { function getBCName ( ) public pure returns (string memory){ return "BC" ; } function getName ( ) public pure override (B,C) returns (string memory) { return super .getName (); } }
selfDestruct 销毁智能合约 下面不建议用selfdestruct ,考虑销毁合同的替代方法,例如将资金转移到指定地址,而不是完全销毁合同
assembly 内联汇编 内联汇编指的是掺杂汇编语言,类似调用shell命令
去中心化交易所实现 这块待添加
合约、时间与账号“加锁” 转账前加锁 不让转账,超过时间才能转账
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 pragma solidity ^0.8 .2 ; import "@openzeppelin/contracts/token/ERC20/ERC20.sol" ;import "@openzeppelin/contracts//access/Ownable.sol" ;contract ThinkingChain is ERC20 ,Ownable { bool public isLocked = false ; uint public timeLock = block.timestamp + 1 minutes; constructor ( ) ERC20 ("ThinkingChain" ,"T" ){ _mint (msg.sender , 100000 * 10 ** decimals ()); } function transfer (address _to,uint256 _amount ) public override returns (bool) { require (block.timestamp %3EtimeLock,"Its not time yet" ); require (isLocked == false ,"Transfer was locked" ); return super .transfer (_to,_amount); } function setLock ( ) public onlyOwner returns (bool) { isLocked = true ; return true ; } }
encode方法差异 尽量多采取A和D合约的方式,调用其他合约的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 pragma solidity >=0.7 .0 <0.9 .0 ; contract A { function calllBFunction (address _address,uint256 _num,string memory _message ) public returns (bool) { (bool success,) = _address.call ( abi.encodeWithSignature ("bFunction(uint256,string)" ,_num,_message) ); return success; } } contract C { function calllBFunction (address _address,uint256 _num,string memory _message ) public returns (bool) { bytes4 sig = bytes4 (keccak256 ("bFunction(uint256,string)" )); bytes memory _bNum = abi.encode (_num); bytes memory _bMessage = abi.encode (_message); (bool success,) = _address.call ( abi.encodePacked (sig,_bNum,_bMessage) ); return success; } } contract D { function calllBFunction (address _address,uint256 _num,string memory _message ) public returns (bool) { bytes4 sig = bytes4 (keccak256 ("bFunction(uint256,string)" )); (bool success,) = _address.call ( abi.encodeWithSelector (sig, _num,_message) ); return success; } } contract E { function calllBFunction (address _address,uint256 _num,string memory _message ) public returns (bool) { B contractB = B (_address); contractB.bFunction (_num, _message); return true ; } } contract B { uint256 public num; string public message; function bFunction (uint256 _num,string memory _message ) public returns (uint256,string memory ) { num = _num; message = _message; return (num,message); } }
Call 和delegateCall的区别 最大的区别就在于 call 调用B方法 ,获取num是存储在B地址下的,而delegatecall 获取的num是存储在A合约地址下
delegatecall 可以用于升级A合约,假设A合约中的方法setnum 需要修改,一旦部署num值是不让修改的,这时候可以部署一个新合约B,在setNum方法里修改,这样调用B方法 ,但是num值改的是A地址的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 pragma solidity ^0.8 .15 ; contract A { uint private num; function setNum (uint _num ) public { num = _num + 1 ; } function getNum ( ) public view returns (uint ){ return num ; } function bSetNum (address _bAddress,uint _num ) public { B b = B (_bAddress); b.setNum (_num); } function bSetNumCall (address _bAddress,uint _num ) public { (bool res,) = _bAddress.call (abi.encodeWithSignature ("setNum(uint256)" , _num)); if (!res) revert (); } function bSetNumDeleGateCall (address _bAddress,uint _num ) public { (bool res,) = _bAddress.delegatecall (abi.encodeWithSignature ("setNum(uint256)" , _num)); if (!res) revert (); } } contract B { uint private num; function setNum (uint _num ) public { num = _num + 2 ; } function getNum ( ) public view returns (uint ){ return num ; } }
管理员权限 Ownable 使用openzippelin的方法 onlyOwner modifier修改器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pragma solidity ^0.8 .9 ; import "@openzeppelin/contracts/token/ERC20/ERC20.sol" ;import "@openzeppelin/contracts/access/Ownable.sol" ;contract MyToken is ERC20 , Ownable { constructor ( ) ERC20 ("ThinkingChain" , "TKC" ) { _mint (msg.sender , 100000 * 10 ** decimals ()); } function mint (address to, uint256 amount ) public onlyOwner { _mint (to, amount); } }
hardhat 教程 hardhat教程
官方教程
官方教程2
ERC20接口解释 // SPDX-License-Identifier:MIT
pragma solidity 0.8.17;
interface IERC20 {
//发行的代币总量
function totalSupply() external view returns (uint256);
//某地址余额
function balanceOf(address account) external view returns (uint256);
//从当前账户对某个地址转amount的钱
function transfer(address account, uint256 amount) external returns (bool);
//授权某个账户可以用你的钱(用多少钱是指定的)
function approve(address spender, uint256 amount) external returns (bool);
//你授权的账户还可以有多少你授权的钱可以用
function allowance(address owner, address spender) external view returns (uint256);
//授权用户的转账方法,只针对授权用户使用
function transferFrom(address from,address to,uint256 amount) external returns (bool);
//转账时触发转账事件
event Transfer(address indexed from, address indexed to, uint256 value);
//授权时触发授权事件
event Approval(address indexed owner, address indexed spender, uint256 value);
}