1234567891011121314151617import {IKeyringPair} from '@polkadot/types/types';18import {GAS_ARGS} from './util/helpers';1920import {itEth, expect, usingEthPlaygrounds, EthUniqueHelper} from './util/playgrounds';2122describe('EVM payable contracts', () => {23 let donor: IKeyringPair;2425 before(async function() {26 await usingEthPlaygrounds(async (_, privateKey) => {27 donor = privateKey('//Alice');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);35 const realContractV1 = await deployRealContractV1(helper, deployer);36 const realContractV1proxy = new helper.web3!.eth.Contract(realContractV1.options.jsonInterface, proxyContract.options.address, {from: caller, ...GAS_ARGS});37 await proxyContract.methods.updateVersion(realContractV1.options.address).send();38 39 await realContractV1proxy.methods.flip().send();40 await realContractV1proxy.methods.flip().send();41 await realContractV1proxy.methods.flip().send();42 const value1 = await realContractV1proxy.methods.getValue().call();43 const flipCount1 = await realContractV1proxy.methods.getFlipCount().call();44 expect(flipCount1).to.be.equal('3');45 expect(value1).to.be.equal(true);46 const realContractV2 = await deployRealContractV2(helper, deployer);47 const realContractV2proxy = new helper.web3!.eth.Contract(realContractV2.options.jsonInterface, proxyContract.options.address, {from: caller, ...GAS_ARGS});48 await proxyContract.methods.updateVersion(realContractV2.options.address).send();49 await realContractV2proxy.methods.flip().send();50 await realContractV2proxy.methods.flip().send();51 const value2 = await realContractV2proxy.methods.getValue().call();52 const flipCount2 = await realContractV2proxy.methods.getFlipCount().call();53 expect(value2).to.be.equal(true);54 expect(flipCount2).to.be.equal('1');55 });5657 async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {58 return await helper.ethContract.deployByCode(deployer, 'ProxyContract', `59 // SPDX-License-Identifier: UNLICENSED60 pragma solidity ^0.8.6;61 62 contract ProxyContract {63 event NewEvent(uint data);64 receive() external payable {}65 bytes32 private constant implementationSlot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1);66 constructor() {}67 function updateVersion(address newContractAddress) external {68 bytes32 slot = implementationSlot;69 assembly {70 sstore(slot, newContractAddress)71 }72 }73 fallback() external {74 bytes32 slot = implementationSlot;75 assembly {76 let ptr := mload(0x40)77 let contractAddress := sload(slot)78 79 calldatacopy(ptr, 0, calldatasize())80 81 let result := delegatecall(gas(), contractAddress, ptr, calldatasize(), 0, 0)82 let size := returndatasize()83 84 returndatacopy(ptr, 0, size)85 86 switch result87 case 0 { revert(ptr, size) }88 default { return(ptr, size) }89 }90 }91 }92 93 interface RealContract {94 function flip() external;95 function getValue() external view returns (bool);96 function getFlipCount() external view returns (uint);97 }`);98 }99100 async function deployRealContractV1(helper: EthUniqueHelper, deployer: string) {101 return await helper.ethContract.deployByCode(deployer, 'RealContractV1', `102 // SPDX-License-Identifier: UNLICENSED103 pragma solidity ^0.8.6;104 105 contract RealContractV1 {106 bool value = false;107 uint flipCount = 0;108 function flip() external {109 value = !value;110 flipCount++;111 }112 function getValue() external view returns (bool) {113 return value;114 }115 function getFlipCount() external view returns (uint) {116 return flipCount;117 }118 }`);119 }120121 async function deployRealContractV2(helper: EthUniqueHelper, deployer: string) {122 return await helper.ethContract.deployByCode(deployer, 'RealContractV2', `123 // SPDX-License-Identifier: UNLICENSED124 pragma solidity ^0.8.6;125 126 contract RealContractV2 {127 bool value = false;128 uint flipCount = 10;129 function flip() external {130 value = !value;131 flipCount--;132 }133 function getValue() external view returns (bool) {134 return value;135 }136 function getFlipCount() external view returns (uint) {137 return flipCount;138 }139 }`);140 }141});