1234567891011121314151617import type {IKeyringPair} from '@polkadot/types/types';1819import {itEth, expect, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';20import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';2122describe('EVM payable contracts', () => {23 let donor: IKeyringPair;2425 before(async function() {26 await usingEthPlaygrounds(async (_, privateKey) => {27 donor = await privateKey({url: import.meta.url});28 });29 });3031 itEth('Update proxy contract', async({helper}) => {32 const deployer = await helper.eth.createAccountWithBalance(donor);33 const caller = await helper.eth.createAccountWithBalance(donor);34 const proxyContract = await deployProxyContract(helper, deployer);3536 const realContractV1 = await deployRealContractV1(helper, deployer);37 const realContractV1proxy = new helper.web3!.eth.Contract(realContractV1.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS});38 await proxyContract.methods.updateVersion(realContractV1.options.address).send();3940 await realContractV1proxy.methods.flip().send();41 await realContractV1proxy.methods.flip().send();42 await realContractV1proxy.methods.flip().send();43 const value1 = await realContractV1proxy.methods.getValue().call();44 const flipCount1 = await realContractV1proxy.methods.getFlipCount().call();45 expect(flipCount1).to.be.equal('3');46 expect(value1).to.be.equal(true);4748 const realContractV2 = await deployRealContractV2(helper, deployer);49 const realContractV2proxy = new helper.web3!.eth.Contract(realContractV2.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS});50 await proxyContract.methods.updateVersion(realContractV2.options.address).send();5152 await realContractV2proxy.methods.flip().send();53 await realContractV2proxy.methods.flip().send();54 await realContractV2proxy.methods.setStep(5).send();55 await realContractV2proxy.methods.increaseFlipCount().send();56 const value2 = await realContractV2proxy.methods.getValue().call();57 const flipCount2 = await realContractV2proxy.methods.getFlipCount().call();58 expect(value2).to.be.equal(true);59 expect(flipCount2).to.be.equal('6');60 });6162 async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {63 return await helper.ethContract.deployByCode(deployer, 'ProxyContract', `64 // SPDX-License-Identifier: UNLICENSED65 pragma solidity ^0.8.6;66 67 contract ProxyContract {68 event NewEvent(uint data);69 receive() external payable {}70 bytes32 private constant implementationSlot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1);71 constructor() {}72 function updateVersion(address newContractAddress) external {73 bytes32 slot = implementationSlot;74 assembly {75 sstore(slot, newContractAddress)76 }77 }78 fallback() external {79 bytes32 slot = implementationSlot;80 assembly {81 let ptr := mload(0x40)82 let contractAddress := sload(slot)83 84 calldatacopy(ptr, 0, calldatasize())85 86 let result := delegatecall(gas(), contractAddress, ptr, calldatasize(), 0, 0)87 let size := returndatasize()88 89 returndatacopy(ptr, 0, size)90 91 switch result92 case 0 { revert(ptr, size) }93 default { return(ptr, size) }94 }95 }96 }97 98 interface RealContract {99 function flip() external;100 function getValue() external view returns (bool);101 function getFlipCount() external view returns (uint);102 }`);103 }104105 async function deployRealContractV1(helper: EthUniqueHelper, deployer: string) {106 return await helper.ethContract.deployByCode(deployer, 'RealContractV1', `107 // SPDX-License-Identifier: UNLICENSED108 pragma solidity ^0.8.6;109 110 contract RealContractV1 {111 bool value = false;112 uint flipCount = 0;113 function flip() external {114 value = !value;115 flipCount++;116 }117 function getValue() external view returns (bool) {118 return value;119 }120 function getFlipCount() external view returns (uint) {121 return flipCount;122 }123 }`);124 }125126 async function deployRealContractV2(helper: EthUniqueHelper, deployer: string) {127 return await helper.ethContract.deployByCode(deployer, 'RealContractV2', `128 // SPDX-License-Identifier: UNLICENSED129 pragma solidity ^0.8.6;130 131 contract RealContractV2 {132 bool value = false;133 uint flipCount = 10;134 uint step = 1;135 function flip() external {136 value = !value;137 flipCount--;138 }139 function setStep(uint value) external {140 step = value;141 }142 function increaseFlipCount() external {143 flipCount = flipCount + step;144 }145 function getValue() external view returns (bool) {146 return value;147 }148 function getFlipCount() external view returns (uint) {149 return flipCount;150 }151 }`);152 }153});