pragmasolidity>=0.8.0;//important
// EIP-3561 信任最小化代理实现 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3561.md
// 基于 EIP-1967 可升级性代理: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1967.md
contractTrustMinimizedProxy{eventUpgraded(addressindexedtoLogic);eventAdminChanged(addressindexedpreviousAdmin,addressindexednewAdmin);eventNextLogicDefined(addressindexednextLogic,uintearliestArrivalBlock);eventProposingUpgradesRestrictedUntil(uintblock,uintnextProposedLogicEarliestArrival);eventNextLogicCanceled();eventZeroTrustPeriodSet(uintblocks);bytes32internalconstantADMIN_SLOT=0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;bytes32internalconstantLOGIC_SLOT=0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;bytes32internalconstantNEXT_LOGIC_SLOT=0x19e3fabe07b65998b604369d85524946766191ac9434b39e27c424c976493685;bytes32internalconstantNEXT_LOGIC_BLOCK_SLOT=0xe3228ec3416340815a9ca41bfee1103c47feb764b4f0f4412f5d92df539fe0ee;bytes32internalconstantPROPOSE_BLOCK_SLOT=0x4b50776e56454fad8a52805daac1d9fd77ef59e4f1a053c342aaae5568af1388;bytes32internalconstantZERO_TRUST_PERIOD_SLOT=0x7913203adedf5aca5386654362047f05edbd30729ae4b0351441c46289146720;constructor()payable{require(ADMIN_SLOT==bytes32(uint256(keccak256('eip1967.proxy.admin'))-1)&&LOGIC_SLOT==bytes32(uint256(keccak256('eip1967.proxy.implementation'))-1)&&NEXT_LOGIC_SLOT==bytes32(uint256(keccak256('eip3561.proxy.next.logic'))-1)&&NEXT_LOGIC_BLOCK_SLOT==bytes32(uint256(keccak256('eip3561.proxy.next.logic.block'))-1)&&PROPOSE_BLOCK_SLOT==bytes32(uint256(keccak256('eip3561.proxy.propose.block'))-1)&&ZERO_TRUST_PERIOD_SLOT==bytes32(uint256(keccak256('eip3561.proxy.zero.trust.period'))-1));_setAdmin(msg.sender);}modifierIfAdmin(){if(msg.sender==_admin()){_;}else{_fallback();}}function_logic()internalviewreturns(addresslogic){assembly{logic:=sload(LOGIC_SLOT)}}function_nextLogic()internalviewreturns(addressnextLogic){assembly{nextLogic:=sload(NEXT_LOGIC_SLOT)}}function_proposeBlock()internalviewreturns(uintb){assembly{b:=sload(PROPOSE_BLOCK_SLOT)}}function_nextLogicBlock()internalviewreturns(uintb){assembly{b:=sload(NEXT_LOGIC_BLOCK_SLOT)}}function_zeroTrustPeriod()internalviewreturns(uintztp){assembly{ztp:=sload(ZERO_TRUST_PERIOD_SLOT)}}function_admin()internalviewreturns(addressadm){assembly{adm:=sload(ADMIN_SLOT)}}function_setAdmin(addressnewAdm)internal{assembly{sstore(ADMIN_SLOT,newAdm)}}functionchangeAdmin(addressnewAdm)externalIfAdmin{emitAdminChanged(_admin(),newAdm);_setAdmin(newAdm);}functionupgrade(bytescalldatadata)externalIfAdmin{require(block.number>=_nextLogicBlock(),'too soon');addresslogic;assembly{logic:=sload(NEXT_LOGIC_SLOT)sstore(LOGIC_SLOT,logic)}(boolsuccess,)=logic.delegatecall(data);require(success,'failed to call');emitUpgraded(logic);}fallback()externalpayable{_fallback();}receive()externalpayable{_fallback();}function_fallback()internal{require(msg.sender!=_admin());_delegate(_logic());}functioncancelUpgrade()externalIfAdmin{addresslogic;assembly{logic:=sload(LOGIC_SLOT)sstore(NEXT_LOGIC_SLOT,logic)}emitNextLogicCanceled();}functionprolongLock(uintb)externalIfAdmin{require(b>_proposeBlock(),'can be only set higher');assembly{sstore(PROPOSE_BLOCK_SLOT,b)}emitProposingUpgradesRestrictedUntil(b,b+_zeroTrustPeriod());}functionsetZeroTrustPeriod(uintblocks)externalIfAdmin{// before this set at least once acts like a normal eip 1967 transparent proxy
// 在至少设置一次之前,其行为类似于正常的 eip 1967 透明代理
uintztp;assembly{ztp:=sload(ZERO_TRUST_PERIOD_SLOT)}require(blocks>ztp,'can be only set higher');assembly{sstore(ZERO_TRUST_PERIOD_SLOT,blocks)}_updateNextBlockSlot();emitZeroTrustPeriodSet(blocks);}function_updateNextBlockSlot()internal{uintnlb=block.number+_zeroTrustPeriod();assembly{sstore(NEXT_LOGIC_BLOCK_SLOT,nlb)}}function_setNextLogic(addressnl)internal{require(block.number>=_proposeBlock(),'too soon');_updateNextBlockSlot();assembly{sstore(NEXT_LOGIC_SLOT,nl)}emitNextLogicDefined(nl,block.number+_zeroTrustPeriod());}functionproposeTo(addressnewLogic,bytescalldatadata)externalpayableIfAdmin{if(_zeroTrustPeriod()==0||_logic()==address(0)){_updateNextBlockSlot();assembly{sstore(LOGIC_SLOT,newLogic)}(boolsuccess,)=newLogic.delegatecall(data);require(success,'failed to call');emitUpgraded(newLogic);}else{_setNextLogic(newLogic);}}function_delegate(addresslogic_)internal{assembly{calldatacopy(0,0,calldatasize())letresult:=delegatecall(gas(),logic_,0,calldatasize(),0,0)returndatacopy(0,0,returndatasize())switchresultcase0{revert(0,returndatasize())}default{return(0,returndatasize())}}}}