Limitless CTF Exchange 智能合約分析:基於 Polymarket 的 Safe 4337 擴展架構
生成提示詞
請深入分析 Limitless Labs CTF Exchange 智能合約:
1. Clone limitless-ctf-exchange 源代碼
2. 與 Polymarket CTF Exchange 進行差異比較
3. 分析 Safe 4337 賬戶抽象整合方式
4. 研究雙工廠架構(Proxy + Safe)設計
5. 解析自定義 SignatureType 擴展
6. 繪製 Mermaid 對比圖說明架構差異
7. 以繁體中文撰寫工程級深度文章
執行摘要
Limitless Labs CTF Exchange 是基於 Polymarket CTF Exchange 的分叉版本,新增了重要的 Safe 4337 賬戶抽象支援。本文將深入分析其與原版的差異:
- Safe 4337 整合:原生支援 ERC-4337 賬戶抽象錢包
- 雙工廠架構:同時管理 Polymarket Proxy 和 Limitless Safe
- 三種簽名類型:EOA、POLY_PROXY、LIMITLESS_SAFE
- CREATE2 地址推導:確定性錢包地址計算
- 域名分離:獨立的 EIP712 簽名域
目錄
1. Limitless vs Polymarket 架構對比
1.1 整體架構差異
flowchart TB
subgraph Limitless["Limitless CTF Exchange"]
LCTF[CTFExchange]
LSig[Signatures Mixin]
LFactory[PolyFactoryHelper]
LSigTypes["簽名類型"]
LEOA[EOA]
LProxy[POLY_PROXY]
LSafe[LIMITLESS_SAFE]
LLibs["地址推導庫"]
LPolyProxy[PolyProxyLib]
LPolySafe[PolySafeLib]
LSafeLib[SafeLib ⭐新增]
LCTF --> LSig
LSig --> LSigTypes
LSigTypes --> LEOA
LSigTypes --> LProxy
LSigTypes --> LSafe
LSig --> LFactory
LFactory --> LLibs
LLibs --> LPolyProxy
LLibs --> LPolySafe
LLibs --> LSafeLib
end
subgraph Polymarket["Polymarket CTF Exchange"]
PCTF[CTFExchange]
PSig[Signatures Mixin]
PSigTypes["簽名類型"]
PEOA[EOA]
PProxy[POLY_PROXY]
PGnosis[POLY_GNOSIS_SAFE]
P1271[POLY_1271]
PLibs["地址推導庫"]
PPolyProxy[PolyProxyLib]
PPolySafe[PolySafeLib]
PCTF --> PSig
PSig --> PSigTypes
PSigTypes --> PEOA
PSigTypes --> PProxy
PSigTypes --> PGnosis
PSigTypes --> P1271
PSig --> PLibs
PLibs --> PPolyProxy
PLibs --> PPolySafe
end
1.2 關鍵差異表
| 特性 | Polymarket | Limitless | 影響 |
|---|---|---|---|
| EIP712 域名 | Polymarket CTF Exchange | Limitless CTF Exchange | 訂單不可跨平台使用 |
| 簽名類型 | 4 種 (EOA, POLY_PROXY, POLY_GNOSIS_SAFE, POLY_1271) | 3 種 (EOA, POLY_PROXY, LIMITLESS_SAFE) | 不同錢包支援策略 |
| Safe 實作 | Gnosis Safe (標準) | Safe 4337 (賬戶抽象) | 支援 Gas 代付 |
| 工廠數量 | 2 個 (Proxy + Safe) | 2 個 (Proxy + Safe) | 相同架構 |
| Safe 地址 | 傳入 implementation | 硬編碼地址 | 不同部署模式 |
1.3 主合約對比
Polymarket CTFExchange.sol:
contract CTFExchange is
BaseExchange,
Auth,
Assets,
Fees,
Pausable,
AssetOperations,
Hashing("Polymarket CTF Exchange", "1"), // 原版域名
NonceManager,
Registry,
Signatures,
Trading
{ }
Limitless CTFExchange.sol:
contract CTFExchange is
BaseExchange,
Auth,
Assets,
Fees,
Pausable,
AssetOperations,
Hashing("Limitless CTF Exchange", "1"), // ⭐ 修改域名
NonceManager,
Registry,
Signatures,
Trading
{ }
2. 簽名類型擴展
2.1 SignatureType 枚舉變更
Polymarket 版本:
enum SignatureType {
EOA, // 普通外部帳戶
POLY_PROXY, // Polymarket Proxy 錢包
POLY_GNOSIS_SAFE, // Gnosis Safe 多簽
POLY_1271 // EIP1271 合約錢包
}
Limitless 版本:
enum SignatureType {
EOA, // 普通外部帳戶
POLY_PROXY, // Polymarket Proxy 錢包(保持兼容)
LIMITLESS_SAFE // ⭐ 新增:Limitless Safe 4337
}
2.2 簽名驗證實作
Limitless Signatures.sol:
function isValidSignature(
address signer,
address associated,
bytes32 structHash,
bytes memory signature,
SignatureType signatureType
) internal view returns (bool) {
if (signatureType == SignatureType.EOA) {
return verifyEOASignature(signer, associated, structHash, signature);
}
else if (signatureType == SignatureType.LIMITLESS_SAFE) {
// ⭐ 新增的 Safe 4337 驗證
return verifySafeSignature(signer, associated, structHash, signature);
}
else {
// POLY_PROXY - 保持與 Polymarket 兼容
return verifyPolyProxySignature(signer, associated, structHash, signature);
}
}
/// @notice Safe 4337 簽名驗證
function verifySafeSignature(
address signer,
address safeAddress,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
// 1. 驗證 ECDSA 簽名
// 2. 驗證計算出的 Safe 地址匹配
return verifyECDSASignature(signer, hash, signature) &&
getSafeAddress(signer) == safeAddress;
}
2.3 為何移除 POLY_1271?
Limitless 移除了 POLY_1271 類型,原因可能是:
- Safe 4337 涵蓋用例:賬戶抽象錢包已支援合約簽名
- 簡化驗證邏輯:減少攻擊面
- 專注核心場景:EOA、Proxy、Safe 覆蓋大部分用戶
3. Safe 4337 整合
3.1 SafeLib 核心實作
檔案路徑: src/exchange/libraries/SafeLib.sol
Limitless 新增了專門的 Safe 4337 地址推導庫:
library SafeLib {
// ⭐ 硬編碼的 Safe 4337 合約地址
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;
address internal constant ZERO_ADDRESS = address(0);
}
3.2 CREATE2 地址推導
/// @notice 計算用戶的 Safe 4337 錢包地址
function getSafeAddress(address signer, address deployer)
internal
pure
returns (address safe)
{
uint256 saltNonce = 0;
// 計算 Proxy 合約的 bytecode hash
bytes32 bytecodeHash = keccak256(
getContractBytecode(safeSingletonAddress)
);
// 獲取初始化代碼
bytes memory initializer = _getInitializerCode(
signer,
ZERO_ADDRESS, // 無額外 token 授權
ZERO_ADDRESS
);
// 計算 salt
bytes32 salt = keccak256(
abi.encodePacked(keccak256(initializer), saltNonce)
);
// CREATE2 地址計算
safe = _computeCreate2Address(deployer, bytecodeHash, salt);
}
3.3 Safe 初始化代碼
/// @notice 生成 Safe 初始化調用數據
function _getInitializerCode(
address owner,
address token, // 可選的 token 授權
address spender // 可選的授權接收者
) internal pure returns (bytes memory) {
// 設定 owners 和閾值
address[] memory owners = new address[](1);
owners[0] = owner;
// 多交易設置:啟用 4337 模組
bytes memory multiSendData = _getMultiSendData(owner, token, spender);
return abi.encodeWithSelector(
ISafe.setup.selector,
owners, // _owners
1, // _threshold
multiSendAddress, // to (MultiSend)
multiSendData, // data (啟用模組)
safe4337ModuleAddress, // fallbackHandler
ZERO_ADDRESS, // paymentToken
0, // payment
ZERO_ADDRESS // paymentReceiver
);
}
3.4 4337 模組啟用
/// @notice 構建多交易數據以啟用 4337 模組
function _getMultiSendData(
address owner,
address token,
address spender
) internal pure returns (bytes memory) {
bytes memory transactions;
// 交易 1: 啟用 4337 模組
bytes memory enableModuleData = abi.encodeWithSelector(
ISafe.enableModule.selector,
safe4337ModuleAddress
);
transactions = abi.encodePacked(
uint8(0), // operation (Call)
addModuleLibAddress, // to
uint256(0), // value
uint256(enableModuleData.length),
enableModuleData
);
// 可選交易 2: Token 授權
if (token != ZERO_ADDRESS && spender != ZERO_ADDRESS) {
bytes memory approveData = abi.encodeWithSelector(
IERC20.approve.selector,
spender,
type(uint256).max
);
transactions = abi.encodePacked(
transactions,
uint8(0),
token,
uint256(0),
uint256(approveData.length),
approveData
);
}
return abi.encodeWithSelector(
IMultiSend.multiSend.selector,
transactions
);
}
3.5 Safe 4337 vs Gnosis Safe 對比
flowchart TB
subgraph Safe4337["Safe 4337 (Limitless)"]
S4User[用戶]
S4Bundler[Bundler]
S4EntryPoint[EntryPoint]
S4Module[4337 Module]
S4Safe[Safe 合約]
S4Exchange[CTFExchange]
S4User -->|簽署 UserOp| S4Bundler
S4Bundler -->|提交| S4EntryPoint
S4EntryPoint -->|驗證| S4Module
S4Module -->|執行| S4Safe
S4Safe -->|交易| S4Exchange
end
subgraph GnosisSafe["Gnosis Safe (Polymarket)"]
GSUser[用戶]
GSRelayer[Relayer]
GSSafe[Safe 合約]
GSExchange[CTFExchange]
GSUser -->|簽署交易| GSRelayer
GSRelayer -->|執行| GSSafe
GSSafe -->|交易| GSExchange
end
Safe 4337 優勢:
- 標準化的 Gas 代付機制
- 更好的跨鏈兼容性
- 內建的批量交易支援
4. 雙工廠架構設計
4.1 PolyFactoryHelper
檔案路徑: src/exchange/mixins/PolyFactoryHelper.sol
Limitless 維護兩套工廠基礎設施:
abstract contract PolyFactoryHelper {
// Polymarket Proxy 工廠
address public proxyFactory;
// Limitless Safe 工廠
address public safeFactory;
/// @notice 獲取用戶的 Polymarket Proxy 錢包地址
function getPolyProxyWalletAddress(address _addr)
public view returns (address)
{
return PolyProxyLib.getProxyWalletAddress(
_addr,
getPolyProxyFactoryImplementation(),
proxyFactory
);
}
/// @notice 獲取用戶的 Safe 4337 錢包地址
function getSafeAddress(address _addr)
public view returns (address)
{
return SafeLib.getSafeAddress(_addr, safeFactory);
}
/// @notice 管理員設置 Proxy 工廠
function setProxyFactory(address _proxyFactory) external onlyAdmin {
proxyFactory = _proxyFactory;
emit ProxyFactorySet(_proxyFactory);
}
/// @notice 管理員設置 Safe 工廠
function setSafeFactory(address _safeFactory) external onlyAdmin {
safeFactory = _safeFactory;
emit SafeFactorySet(_safeFactory);
}
}
4.2 地址推導庫對比
flowchart LR
subgraph PolyProxyLib["PolyProxyLib"]
PP1[輸入: signer, implementation, deployer]
PP2[Salt: keccak256(signer)]
PP3[Bytecode: Proxy 合約]
PP4[CREATE2 計算]
PP1 --> PP2 --> PP4
PP1 --> PP3 --> PP4
end
subgraph PolySafeLib["PolySafeLib (Polymarket)"]
PS1[輸入: signer, implementation, deployer]
PS2[Salt: keccak256(encode(signer))]
PS3[Bytecode: 傳入 implementation]
PS4[CREATE2 計算]
PS1 --> PS2 --> PS4
PS1 --> PS3 --> PS4
end
subgraph SafeLib["SafeLib (Limitless)"]
SL1[輸入: signer, deployer]
SL2[Salt: keccak256(initializer, nonce)]
SL3[Bytecode: 硬編碼 singleton]
SL4[CREATE2 計算]
SL1 --> SL2 --> SL4
SL3 --> SL4
end
4.3 關鍵差異
PolySafeLib (Polymarket):
function getSafeAddress(
address signer,
address implementation, // ⭐ 傳入 implementation
address deployer
) internal pure returns (address safe) {
bytes32 bytecodeHash = keccak256(
getContractBytecode(implementation)
);
bytes32 salt = keccak256(abi.encode(signer));
safe = _computeCreate2Address(deployer, bytecodeHash, salt);
}
SafeLib (Limitless):
function getSafeAddress(
address signer,
address deployer
) internal pure returns (address safe) {
// ⭐ 使用硬編碼 singleton
bytes32 bytecodeHash = keccak256(
getContractBytecode(safeSingletonAddress)
);
// ⭐ 使用 initializer + nonce 作為 salt
bytes memory initializer = _getInitializerCode(signer, ...);
bytes32 salt = keccak256(
abi.encodePacked(keccak256(initializer), saltNonce)
);
safe = _computeCreate2Address(deployer, bytecodeHash, salt);
}
設計權衡:
- Polymarket: 靈活(可更換 implementation)
- Limitless: 簡單(固定使用 Safe 4337)
5. 關鍵差異總結
5.1 功能對比表
| 功能 | Polymarket | Limitless | 說明 |
|---|---|---|---|
| 域名 | Polymarket CTF Exchange | Limitless CTF Exchange | 訂單不互通 |
| EOA 簽名 | ✅ | ✅ | 相同實作 |
| Proxy 錢包 | ✅ | ✅ | 保持兼容 |
| Gnosis Safe | ✅ | ❌ | 移除 |
| Safe 4337 | ❌ | ✅ | 新增 |
| EIP1271 | ✅ | ❌ | 移除 |
| Gas 代付 | 依賴 Relayer | 原生支援 | 更好的 UX |
5.2 用戶體驗影響
flowchart TB
subgraph Polymarket["Polymarket 用戶流程"]
PU1[創建錢包]
PU2[存入 Gas]
PU3[簽署訂單]
PU4[等待 Relayer]
PU5[訂單執行]
PU1 --> PU2 --> PU3 --> PU4 --> PU5
end
subgraph Limitless["Limitless 用戶流程 (Safe 4337)"]
LU1[創建 Safe]
LU2[簽署 UserOp]
LU3[Bundler 代付 Gas]
LU4[訂單執行]
LU1 --> LU2 --> LU3 --> LU4
end
Limitless 優勢:
- 無需預存 Gas(Bundler 代付)
- 更好的隱私保護(UserOp 批處理)
- 標準化的賬戶抽象介面
5.3 技術決策權衡
| 決策 | Polymarket 方案 | Limitless 方案 | 權衡分析 |
|---|---|---|---|
| Safe 版本 | Gnosis Safe 1.x | Safe 4337 | 新版本需更多測試 |
| 地址推導 | 動態 implementation | 硬編碼 | 簡單但較不靈活 |
| 簽名類型 | 4 種 | 3 種 | 更聚焦但較少選擇 |
| 兼容性 | 廣泛支援 | 專注 4337 | 未來導向 |
5.4 源碼文件對比
Polymarket Limitless
─────────────────────────────────────────────────────
libraries/
├── PolyProxyLib.sol ├── PolyProxyLib.sol (相同)
├── PolySafeLib.sol ├── PolySafeLib.sol (相同)
│ └── SafeLib.sol ⭐ (新增)
└── CalculatorHelper.sol └── CalculatorHelper.sol (相同)
mixins/
├── Signatures.sol ├── Signatures.sol (修改)
│ └── 4種簽名類型 │ └── 3種簽名類型
│ ├── PolyFactoryHelper.sol (修改)
│ │ └── 新增 safeFactory
└── ... └── ... (相同)
5.5 訂單結構對比
兩者使用相同的 Order 結構,但 SignatureType 枚舉不同:
// 相同的訂單結構
struct Order {
uint256 salt;
address maker;
address signer;
address taker;
uint256 tokenId;
uint256 makerAmount;
uint256 takerAmount;
uint256 expiration;
uint256 nonce;
uint256 feeRateBps;
Side side;
SignatureType signatureType; // ⭐ 枚舉值不同
bytes signature;
}
重要:由於 SignatureType 枚舉不同,訂單無法在兩個平台間通用。
總結
Limitless Labs 的創新
-
Safe 4337 原生整合
- 首個整合 ERC-4337 的預測市場
- 支援 Bundler 代付 Gas
- 更好的用戶體驗
-
簡化的簽名類型
- 聚焦三種核心類型
- 移除 EIP1271 複雜性
- 更清晰的驗證邏輯
-
硬編碼 Safe 地址
- 簡化部署流程
- 確保一致的地址推導
- 犧牲靈活性換取簡單性
適用場景
| 場景 | 推薦平台 |
|---|---|
| 傳統 EOA 用戶 | 兩者皆可 |
| 需要多簽 | Polymarket (Gnosis Safe) |
| 需要 Gas 代付 | Limitless (Safe 4337) |
| 合約錢包 (EIP1271) | Polymarket |
| 未來賬戶抽象生態 | Limitless |
關鍵文件路徑
Limitless 新增/修改:
├── src/exchange/libraries/SafeLib.sol # Safe 4337 地址推導
├── src/exchange/mixins/Signatures.sol # 3種簽名類型
├── src/exchange/mixins/PolyFactoryHelper.sol # 雙工廠管理
└── src/exchange/CTFExchange.sol # 域名修改
保持不變:
├── src/exchange/mixins/Trading.sol # 核心交易邏輯
├── src/exchange/libraries/CalculatorHelper.sol # 費用計算
└── src/exchange/libraries/PolyProxyLib.sol # Proxy 地址推導
Limitless Labs CTF Exchange 展示了如何在保持 Polymarket 核心架構的同時,整合 ERC-4337 賬戶抽象標準,為預測市場帶來更好的用戶體驗。