Skip to content

Commit

Permalink
test: upgrade contract while changing vars
Browse files Browse the repository at this point in the history
  • Loading branch information
Uriel Mihura committed Jan 19, 2024
1 parent 95d196d commit 8e04ca6
Show file tree
Hide file tree
Showing 6 changed files with 621 additions and 0 deletions.
8 changes: 8 additions & 0 deletions contracts/solidity/src/YABTransfer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,13 @@ contract YABTransfer is Initializable, OwnableUpgradeable, UUPSUpgradeable {
_snEscrowWithdrawSelector = snEscrowWithdrawSelector;
}

function getEscrowAddress() external view returns (uint256) {
return _snEscrowAddress;
}

function getEscrowWithdrawSelector() external view returns (uint256) {
return _snEscrowWithdrawSelector;
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
126 changes: 126 additions & 0 deletions contracts/solidity/test/Upgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.21;

import "forge-std/Test.sol";
import "../src/YABTransfer.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {YABTransfer_lessVars} from "./mock_contracts/YABTransfer_lessVars.sol";
import {YABTransfer_reorgVars} from "./mock_contracts/YABTransfer_reorgVars.sol";
import {YABTransfer_moreVars_before} from "./mock_contracts/YABTransfer_moreVars_before.sol";
import {YABTransfer_moreVars_after} from "./mock_contracts/YABTransfer_moreVars_after.sol";


contract TransferTest is Test {
address public deployer = address(0xB321099cf86D9BB913b891441B014c03a6CcFc54);
address public marketMaker;

YABTransfer public yab;
ERC1967Proxy public proxy;
YABTransfer public yab_caller;

function setUp() public {
vm.startPrank(deployer);

address snMessagingAddress = 0xde29d060D45901Fb19ED6C6e959EB22d8626708e;
uint256 snEscrowAddress = 0x0;
uint256 snEscrowWithdrawSelector = 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77;
marketMaker = 0xda963fA72caC2A3aC01c642062fba3C099993D56;

yab = new YABTransfer();
proxy = new ERC1967Proxy(address(yab), "");
yab_caller = YABTransfer(address(proxy));
yab_caller.initialize(snMessagingAddress, snEscrowAddress, snEscrowWithdrawSelector, marketMaker);

vm.stopPrank();
}

function deploy_and_upgrade_lessVars() public returns (YABTransfer_lessVars){
YABTransfer_lessVars yab_lessVars = new YABTransfer_lessVars();
YABTransfer_lessVars yab_lessVars_caller = YABTransfer_lessVars(address(proxy));
yab_lessVars_caller.upgradeToAndCall(address(yab_lessVars), '');
return yab_lessVars_caller;
}

function deploy_and_upgrade_reorgVars() public returns (YABTransfer_reorgVars){
YABTransfer_reorgVars yab_reorgVars = new YABTransfer_reorgVars();
YABTransfer_reorgVars yab_reorgVars_caller = YABTransfer_reorgVars(address(proxy));
yab_reorgVars_caller.upgradeToAndCall(address(yab_reorgVars), '');
return yab_reorgVars_caller;
}

function deploy_and_upgrade_oldVars() public returns (YABTransfer){
YABTransfer yab_old = new YABTransfer();
YABTransfer yab_old_caller = YABTransfer(address(proxy));
yab_old_caller.upgradeToAndCall(address(yab_old), '');
return yab_old_caller;
}

function deploy_and_upgrade_moreVars_before() public returns (YABTransfer_moreVars_before){
YABTransfer_moreVars_before yab_moreVars_before = new YABTransfer_moreVars_before();
YABTransfer_moreVars_before yab_moreVars_before_caller = YABTransfer_moreVars_before(address(proxy));
yab_moreVars_before_caller.upgradeToAndCall(address(yab_moreVars_before), '');
return yab_moreVars_before_caller;
}

function deploy_and_upgrade_moreVars_after() public returns (YABTransfer_moreVars_after){
YABTransfer_moreVars_after yab_moreVars_after = new YABTransfer_moreVars_after();
YABTransfer_moreVars_after yab_moreVars_after_caller = YABTransfer_moreVars_after(address(proxy));
yab_moreVars_after_caller.upgradeToAndCall(address(yab_moreVars_after), '');
return yab_moreVars_after_caller;
}


// function test_read_values() public { //ok
// assertEq(yab_caller.getEscrowWithdrawSelector(), 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77);
// assertEq(yab_caller.getEscrowAddress(), 0x0);
// }

// function test_should_fail_read_deleted_values() public { //ok?
// vm.startPrank(deployer);
// YABTransfer_lessVars yab_lessVars_caller = deploy_and_upgrade_lessVars();
// vm.expectRevert(); //function does not exist
// yab_caller.getEscrowWithdrawSelector();
// vm.expectRevert(); //function does not exist
// yab_caller.getEscrowAddress();
// vm.stopPrank();
// }

// //WARNING
// function test_read_reorg_values() public { //this test proves reorganizing values in storage IS HIGHLY DANGEROUS
// vm.startPrank(deployer);
// assertEq(yab_caller.getEscrowWithdrawSelector(), 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77);
// assertEq(yab_caller.getEscrowAddress(), 0x0);

// YABTransfer_reorgVars yab_reorgVars_caller = deploy_and_upgrade_reorgVars();

// assertEq(yab_reorgVars_caller.getEscrowWithdrawSelector(), 0x0);
// assertEq(yab_reorgVars_caller.getEscrowAddress(), 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77);
// vm.stopPrank();
// }

// //WARNING
// function test_read_delAndReorg_values() public {//this test proves reorganizing values in storage IS HIGHLY DANGEROUS
// vm.startPrank(deployer);
// assertEq(yab_caller.getEscrowWithdrawSelector(), 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77);
// assertEq(yab_caller.getEscrowAddress(), 0x0);

// YABTransfer_lessVars yab_lessVars_caller = deploy_and_upgrade_lessVars();
// YABTransfer_reorgVars yab_reorgVars_caller = deploy_and_upgrade_reorgVars();

// assertEq(yab_reorgVars_caller.getEscrowWithdrawSelector(), 0x0);
// assertEq(yab_reorgVars_caller.getEscrowAddress(), 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77);
// vm.stopPrank();
// }

// function test_read_var_before() public { //WIP
// vm.startPrank(deployer);
// vm.expectRevert(); //function does not exist
// yab_caller.getNewVarBefore();

// YABTransfer_moreVars_before yab_moreVars_before_caller = ();

// assertEq(yab_moreVars_before_caller.getEscrowWithdrawSelector(), 0x0);
// assertEq(yab_moreVars_before_caller.getEscrowAddress(), 0x15511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77);
// vm.stopPrank();
// }
}
119 changes: 119 additions & 0 deletions contracts/solidity/test/mock_contracts/YABTransfer_lessVars.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.21;

import {IStarknetMessaging} from "starknet/IStarknetMessaging.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";


// This contract is the same as YABTransfer.sol but it does not have:
// _snEscrowAddress and _snEscrowWithdrawSelector storage, and their related functions
contract YABTransfer_lessVars is Initializable, OwnableUpgradeable, UUPSUpgradeable {
struct TransferInfo {
uint256 destAddress;
uint256 amount;
bool isUsed;
}

event Transfer(uint256 indexed orderId, address srcAddress, TransferInfo transferInfo);

mapping(bytes32 => TransferInfo) public transfers;
address private _marketMaker;

IStarknetMessaging private _snMessaging;
// uint256 private _snEscrowAddress;
// uint256 private _snEscrowWithdrawSelector;

constructor() {
_disableInitializers();
}

// no constructors can be used in upgradeable contracts.
function initialize(
address snMessaging,
// uint256 snEscrowAddress,
// uint256 snEscrowWithdrawSelector,
address marketMaker) public initializer {
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();

_snMessaging = IStarknetMessaging(snMessaging);
// _snEscrowAddress = snEscrowAddress;
// _snEscrowWithdrawSelector = snEscrowWithdrawSelector;
_marketMaker = marketMaker;
}


function transfer(uint256 orderId, uint256 destAddress, uint256 amount) external payable onlyOwnerOrMM {
require(destAddress != 0, "Invalid destination address.");
require(amount > 0, "Invalid amount, should be higher than 0.");
require(msg.value == amount, "Invalid amount, should match msg.value.");

bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount));
require(transfers[index].isUsed == false, "Transfer already processed.");

transfers[index] = TransferInfo({destAddress: destAddress, amount: amount, isUsed: true});

(bool success,) = payable(address(uint160(destAddress))).call{value: msg.value}("");

require(success, "Transfer failed.");
emit Transfer(orderId, msg.sender, transfers[index]);
}

function withdraw(uint256 orderId, uint256 destAddress, uint256 amount) external payable onlyOwnerOrMM {
bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount));
TransferInfo storage transferInfo = transfers[index];
require(transferInfo.isUsed == true, "Transfer not found.");

uint256[] memory payload = new uint256[](5);
payload[0] = orderId;
payload[1] = 0;
payload[2] = transferInfo.destAddress;
payload[3] = transferInfo.amount;
payload[4] = 0;

// _snMessaging.sendMessageToL2{value: msg.value}(
// _snEscrowAddress,
// _snEscrowWithdrawSelector,
// payload);
}

// function setEscrowAddress(uint256 snEscrowAddress) external onlyOwner {
// _snEscrowAddress = snEscrowAddress;
// }

// function setEscrowWithdrawSelector(uint256 snEscrowWithdrawSelector) external onlyOwner {
// _snEscrowWithdrawSelector = snEscrowWithdrawSelector;
// }

// function getEscrowAddress() external view returns (uint256) {
// return _snEscrowAddress;
// }

// function getEscrowWithdrawSelector() external view returns (uint256) {
// return _snEscrowWithdrawSelector;
// }


//// MM ACL:

function getMMAddress() external view onlyOwnerOrMM returns (address) {
return _marketMaker;
}

function setMMAddress(address newMMAddress) external onlyOwner {
_marketMaker = newMMAddress;
}

function getOwner() external view returns (address) {
return owner();
}

modifier onlyOwnerOrMM {
require(msg.sender == owner() || msg.sender == _marketMaker, "Only Owner or MM can call this function");
_;
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
125 changes: 125 additions & 0 deletions contracts/solidity/test/mock_contracts/YABTransfer_moreVars_after.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.21;

import {IStarknetMessaging} from "starknet/IStarknetMessaging.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract YABTransfer_moreVars_after is Initializable, OwnableUpgradeable, UUPSUpgradeable {
struct TransferInfo {
uint256 destAddress;
uint256 amount;
bool isUsed;
}

event Transfer(uint256 indexed orderId, address srcAddress, TransferInfo transferInfo);

mapping(bytes32 => TransferInfo) public transfers;
address private _marketMaker;

IStarknetMessaging private _snMessaging;
uint256 private _snEscrowAddress;
uint256 private _snEscrowWithdrawSelector;
uint256 private _newVarAfter;

constructor() {
_disableInitializers();
}

// no constructors can be used in upgradeable contracts.
function initialize(
address snMessaging,
uint256 snEscrowAddress,
uint256 snEscrowWithdrawSelector,
address marketMaker) public initializer {
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();

_snMessaging = IStarknetMessaging(snMessaging);
_snEscrowAddress = snEscrowAddress;
_snEscrowWithdrawSelector = snEscrowWithdrawSelector;
_marketMaker = marketMaker;
}


function transfer(uint256 orderId, uint256 destAddress, uint256 amount) external payable onlyOwnerOrMM {
require(destAddress != 0, "Invalid destination address.");
require(amount > 0, "Invalid amount, should be higher than 0.");
require(msg.value == amount, "Invalid amount, should match msg.value.");

bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount));
require(transfers[index].isUsed == false, "Transfer already processed.");

transfers[index] = TransferInfo({destAddress: destAddress, amount: amount, isUsed: true});

(bool success,) = payable(address(uint160(destAddress))).call{value: msg.value}("");

require(success, "Transfer failed.");
emit Transfer(orderId, msg.sender, transfers[index]);
}

function withdraw(uint256 orderId, uint256 destAddress, uint256 amount) external payable onlyOwnerOrMM {
bytes32 index = keccak256(abi.encodePacked(orderId, destAddress, amount));
TransferInfo storage transferInfo = transfers[index];
require(transferInfo.isUsed == true, "Transfer not found.");

uint256[] memory payload = new uint256[](5);
payload[0] = orderId;
payload[1] = 0;
payload[2] = transferInfo.destAddress;
payload[3] = transferInfo.amount;
payload[4] = 0;

_snMessaging.sendMessageToL2{value: msg.value}(
_snEscrowAddress,
_snEscrowWithdrawSelector,
payload);
}

function setEscrowAddress(uint256 snEscrowAddress) external onlyOwner {
_snEscrowAddress = snEscrowAddress;
}

function setEscrowWithdrawSelector(uint256 snEscrowWithdrawSelector) external onlyOwner {
_snEscrowWithdrawSelector = snEscrowWithdrawSelector;
}

function getEscrowAddress() external view returns (uint256) {
return _snEscrowAddress;
}

function getEscrowWithdrawSelector() external view returns (uint256) {
return _snEscrowWithdrawSelector;
}

function getNewVarAfter() external view returns (uint256) {
return _newVarAfter;
}

function setNewVarAfter(uint256 newValue) external {
_newVarAfter = newValue;
}


//// MM ACL:

function getMMAddress() external view onlyOwnerOrMM returns (address) {
return _marketMaker;
}

function setMMAddress(address newMMAddress) external onlyOwner {
_marketMaker = newMMAddress;
}

function getOwner() external view returns (address) {
return owner();
}

modifier onlyOwnerOrMM {
require(msg.sender == owner() || msg.sender == _marketMaker, "Only Owner or MM can call this function");
_;
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
Loading

0 comments on commit 8e04ca6

Please sign in to comment.