Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgrade safe proxy lib #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions addresses.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"84531": {
"ctfExchange": "0x54d696A602343063000B25a51734E3BbE0Ec80a2",
"ctfExchange": "0x516989fc9e4694d0c27d2199df0bac5428514df4",
"rewardDistributor": "0x93A4dB1e2854F01fB3Ff67BcAEAb7c470042CF58",
"ctf": "0x828Fd8B3544021590bA9F9A994ADDB8B44DDd951",
"usdc": "0xD7788FfC73C9AE39CE24dfc1098b375792dD42Ac"
},
"8453": {
"ctfExchange": "0x8B8fb0602c732a1c312e65D9a99Fc4c798d3EDe0",
"ctfExchange": "0xeE4d2Ae1C02d71f4E072991cfFDF0CdB80865cF0",
"rewardDistributor": "0xE895CaE6B705d584b03cd82Fdd57cf7F8c52FaDB",
"ctf": "0xc9c98965297bc527861c898329ee280632b76e18",
"usdc": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
Expand Down
244 changes: 122 additions & 122 deletions broadcast/ExchangeDeployment.s.sol/8453/deployExchange-latest.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/8453/run-1738848222.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/84532/deployExchange-latest.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/84532/run-1738629417.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/84532/run-1738629811.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/84532/run-1738658582.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/84532/run-1738660026.json

Large diffs are not rendered by default.

310 changes: 310 additions & 0 deletions broadcast/ExchangeDeployment.s.sol/84532/run-1738715543.json

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/exchange/interfaces/ISafe.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity <0.9.0;

interface ISafe {
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) external;
}
157 changes: 157 additions & 0 deletions src/exchange/libraries/SafeLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// SPDX-License-Identifier: MIT
pragma solidity <0.9.0;

import {ISafe} from "exchange/interfaces/ISafe.sol";


/// @title SafeLib
/// @notice Helper library to compute Limitless Safe 4337 addresses
library SafeLib {
address public constant ZERO_ADDRESS = address(0);

/// @notice Hardcoded addresses for Safe-related contracts used in Limitless Safe 4337.
/// @dev These addresses are fixed because we rely on a specific set of Safe versions:
/// - Safe 4337 Module: v0.2.0
/// - Safe Proxy Factory: v1.4.1
/// - Add Modules Library: v1.3.0
/// - Safe Singleton: v1.4.1
/// - Multi Send: v1.4.1
///
/// If future implementations require different versions, we will extend the signature type
/// and introduce a new type with updated implementations.
///
/// Due to this strict version dependency and our approach of adding new signature types
/// as needed, we intentionally avoid maintaining getters and setters for these addresses.
/// Since they are not expected to change, additional management functions would be redundant.
address public constant addModuleLibAddress = 0x8EcD4ec46D4D2a6B64fE960B3D64e8B94B2234eb;
address public constant safe4337ModuleAddress = 0xa581c4A4DB7175302464fF3C06380BC3270b4037;
address public constant safeProxyFactoryAddress = 0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67;
address public constant safeSingletonAddress = 0x41675C099F32341bf84BFc5382aF534df5C7461a;
address public constant multiSendAddress = 0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526;

struct InternalTx {
address to;
bytes data;
uint256 value;
uint8 operation;
}

bytes private constant proxyCreationCode =
hex"608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564";

/// @notice Gets the Limitless Safe 4337 address for a signer
/// @param signer - Address of the signer
/// @param deployer - Address of the deployer contract
// function getSafeAddress(address signer, address implementation, address deployer)
function getSafeAddress(address signer, address deployer)
internal
pure
returns (address safe)
{

uint256 saltNonce = 0;

bytes32 bytecodeHash = keccak256(getContractBytecode(safeSingletonAddress));
bytes memory initializer = _getInitializerCode(
signer,
ZERO_ADDRESS, // erc20TokenAddress
ZERO_ADDRESS // paymasterAddress
);

bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));

safe = _computeCreate2Address(deployer, bytecodeHash, salt);
}

function getContractBytecode(address masterCopy) internal pure returns (bytes memory) {
return abi.encodePacked(proxyCreationCode, abi.encode(masterCopy));
}

function _computeCreate2Address(address deployer, bytes32 bytecodeHash, bytes32 salt)
internal
pure
returns (address)
{
bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash));
return address(uint160(uint256(_data)));
}

function _getInitializerCode(
address owner,
address erc20TokenAddress,
address paymasterAddress
) internal pure returns (bytes memory) {
InternalTx[] memory setupTxs = new InternalTx[](
erc20TokenAddress != ZERO_ADDRESS && paymasterAddress != ZERO_ADDRESS ? 2 : 1
);

// Enable module transaction
setupTxs[0] = InternalTx({
to: addModuleLibAddress,
data: _enableModuleCallData(),
value: 0,
operation: 1 // DelegateCall
});

// Add approve transaction if needed
if (erc20TokenAddress != ZERO_ADDRESS && paymasterAddress != ZERO_ADDRESS) {
setupTxs[1] = InternalTx({
to: erc20TokenAddress,
data: _generateApproveCallData(paymasterAddress),
value: 0,
operation: 0 // Call
});
}

bytes memory multiSendCallData = _encodeMultiSend(setupTxs);

address[] memory owners = new address[](1);
owners[0] = owner;

return abi.encodeWithSelector(
ISafe.setup.selector,
owners,
1, // threshold
multiSendAddress,
multiSendCallData,
safe4337ModuleAddress,
ZERO_ADDRESS,
0,
payable(ZERO_ADDRESS)
);
}

function _enableModuleCallData() internal pure returns (bytes memory) {
address[] memory modules = new address[](1);
modules[0] = safe4337ModuleAddress;

return abi.encodeWithSignature("enableModules(address[])", modules);
}

function _generateApproveCallData(address spender) internal pure returns (bytes memory) {
return abi.encodeWithSignature("approve(address,uint256)", spender, type(uint256).max);
}

function _encodeMultiSend(InternalTx[] memory txs) internal pure returns (bytes memory) {
bytes memory encodedTxs = "";

for (uint256 i = 0; i < txs.length; i++) {
encodedTxs = bytes.concat(
encodedTxs,
_encodeInternalTransaction(txs[i])
);
}

return abi.encodeWithSignature("multiSend(bytes)", encodedTxs);
}

function _encodeInternalTransaction(InternalTx memory tx) internal pure returns (bytes memory) {
return abi.encodePacked(
tx.operation,
tx.to,
tx.value,
uint256(tx.data.length),
tx.data
);
}
}
12 changes: 6 additions & 6 deletions src/exchange/mixins/PolyFactoryHelper.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity <0.9.0;

import { PolySafeLib } from "../libraries/PolySafeLib.sol";
import { SafeLib } from "../libraries/SafeLib.sol";
import { PolyProxyLib } from "../libraries/PolyProxyLib.sol";

interface IPolyProxyFactory {
Expand All @@ -15,7 +15,7 @@ interface IPolySafeFactory {
abstract contract PolyFactoryHelper {
/// @notice The Polymarket Proxy Wallet Factory Contract
address public proxyFactory;
/// @notice The Polymarket Gnosis Safe Factory Contract
/// @notice The Limitless Safe Factory Contract
address public safeFactory;

event ProxyFactoryUpdated(address indexed oldProxyFactory, address indexed newProxyFactory);
Expand Down Expand Up @@ -43,8 +43,8 @@ abstract contract PolyFactoryHelper {
}

/// @notice Gets the Safe factory implementation address
function getSafeFactoryImplementation() public view returns (address) {
return IPolySafeFactory(safeFactory).masterCopy();
function getSafeFactoryImplementation() public pure returns (address) {
return SafeLib.safeSingletonAddress;
}

/// @notice Gets the Polymarket proxy wallet address for an address
Expand All @@ -53,10 +53,10 @@ abstract contract PolyFactoryHelper {
return PolyProxyLib.getProxyWalletAddress(_addr, getPolyProxyFactoryImplementation(), proxyFactory);
}

/// @notice Gets the Polymarket Gnosis Safe address for an address
/// @notice Gets the Limitless Safe 4337 address for an address
/// @param _addr - The address that owns the proxy wallet
function getSafeAddress(address _addr) public view returns (address) {
return PolySafeLib.getSafeAddress(_addr, getSafeFactoryImplementation(), safeFactory);
return SafeLib.getSafeAddress(_addr, safeFactory);
}

function _setProxyFactory(address _proxyFactory) internal {
Expand Down