Ownbit · 多簽恢復

EVM 多簽:資產存錯網路如何恢復

你有一個 Ownbit 的 EVM 多簽,但資產被轉到了你本來沒計畫的鏈上,或者一條多簽無法操作的鏈上。資金並沒有遺失。具體怎麼做,取決於 Ownbit 是否在那條鏈上支援多簽。

為什麼可以恢復

Ownbit 多簽合約的地址是由它的 部署地址(deploy 地址)及該地址的 nonce 推導出來的,與鏈無關。因此同一個部署地址在任何 EVM 鏈上都會得到相同的合約地址。這是下面所有恢復方法的關鍵。

兩種情況

✓ 支援的鏈

A. 該鏈是 Ownbit 多簽支援的網路

ETHBSCBASEARBPOLYGON

直接在那條鏈上再建立一次多簽即可。因為合約地址只取決於部署地址,在該鏈重新部署會把合約部署到你資金所在的同一個地址,資產隨即可以透過正常的多簽流程轉出。

部署完成後,在該鏈上打開錢包、像平時一樣把資產轉出即可。

不支援的鏈

B. 該鏈不是 Ownbit 多簽支援的網路

例如 Optimism。這裡無法重建多簽,所以改為把一個小小的 Sweeper 合約部署到相同地址,再呼叫它把卡住的資產取出。請按下面的步驟操作。

不支援的鏈上怎麼恢復

把多簽的部署地址作為普通單私鑰錢包匯入,給它充一點 gas,再用它部署 Sweeper。由於地址由部署帳戶推導,Sweeper 會落在持有你卡住資金的那個合約地址上。然後呼叫 sweep() / sweepETH() 把資產全部拉回到部署地址。

開始前

部署地址在目標鏈上必須沒有發過任何轉出交易(nonce 未被使用),否則建立出來的地址會對不上。給它轉入(收款)是沒關係的。還需要該地址上有一點原生 gas(如 Optimism 上的 ETH)。

步驟(不支援的鏈)

匯出多簽的部署私鑰

在 Ownbit 中,對該多簽打開 匯出私鑰,選擇帶有 (MS_DEPLOY_INDEX) 標記的地址——這就是部署你多簽合約的地址。顯示並複製它的私鑰。請離線保管,切勿貼上到任何網站。

選對部署私鑰

注意:如果你的多簽地址不是由多簽錢包本身部署的,而是你手動選擇了某個熱錢包來部署的,那麼這裡要匯出的,必須是那個部署熱錢包的私鑰,而不是該多簽錢包的私鑰。

匯出私鑰 → 選擇 (MS_DEPLOY_INDEX) 地址
匯出私鑰 → 選擇 (MS_DEPLOY_INDEX) 地址

把它匯入為一個臨時的普通錢包

用該私鑰建立 / 匯入錢包。私鑰類型選 ETH,貼上 64 位十六進位私鑰。這個臨時單私鑰錢包現在控制著部署地址。

匯入 → 私鑰類型 ETH,64 位 HEX
匯入 → 私鑰類型 ETH,64 位 HEX

在目標網路上充一點 gas

打開匯入的錢包,切換到目標網路的 ETH(這裡是 ETH · Optimism),確保上面有少量原生 gas。卡住的資產就在這條鏈上你的多簽合約地址上。此時先不要從這個地址轉出任何東西。

匯入的錢包在 Optimism 上——持有少量 ETH 作 gas
匯入的錢包在 Optimism 上——持有少量 ETH 作 gas

部署 Sweeper 合約

發送,選 ETH · Optimism。接收地址填 0x0——在 Ownbit 裡這表示「部署合約」。金額填 0。在確認頁打開進階選項,設定足夠的 Gas Limit(示例為 2,560,000),把下面的 Sweeper 位元組碼貼上到 Hex data。點發送。

Hex data 用哪段位元組碼

這裡 Hex data 要填的位元組碼,請使用下文《Sweeper 位元組碼(部署用)》一節中的完整位元組碼。

千萬不要亂發交易

在使用這個匯入的部署錢包期間,千萬不要隨意發送任何交易。每發送一筆交易都會消耗該地址的 nonce,一旦 nonce 被推進,就再也無法把合約部署到正確的多簽地址,資金將永遠無法取出。

接收地址 0x0 → 金額 0 → Hex data 貼上位元組碼,再發送

核對建立地址與多簽地址是否一致

在區塊瀏覽器上,該交易顯示為合約建立:To [0x…eb2 Created]這個建立出的地址必須等於你的多簽地址。一致,說明 Sweeper 就落在你資金所在位置;不一致請停下——部署地址很可能在這條鏈上已經發過轉出交易了。

如果地址對不上

如果發現地址不一致,先在對應網路的區塊瀏覽器上查看你要恢復的那個多簽地址:找到建立該地址的合約建立交易,確認它當時使用的 nonce(例如 nonce = 3)。然後核對你匯入的部署私鑰,是否與當初部署多簽時用的私鑰一致。如果私鑰確實相同、只是當初部署用的是 nonce = 3,那麼建議你用同一個部署錢包按上面的流程重複部署,連續建立到第 3 次,直到得到與目標一致的地址——而不是隨便發交易去白白消耗 nonce。

合約已建立——確認新地址與多簽地址一致
合約已建立——確認新地址與多簽地址一致

把資產 sweep 回自己

再次點 發送,選 ETH · Optimism,接收地址填剛建立的合約地址(即你的多簽地址,如 0xd3fe…eb2)。金額填 0。在確認頁打開進階選項,設定 Gas Limit,把呼叫資料貼上到 Hex data(見下一節)。點發送。

接收地址 = Sweeper(你的多簽)→ 金額 0 → 貼上 sweep 呼叫資料

完成——資金回到部署錢包

被 sweep 出的資產(這裡是 +1 OP)到達你的部署錢包。現在可以隨意轉走。如果某次 sweep 交易失敗(例如 gas 太低),直接重試即可——不會影響已經部署好的合約。

已恢復——資產回到錢包
已恢復——資產回到錢包

構造 sweep 呼叫資料

一共兩個方法,在步驟 6 中任選一個填入 Hex data

ERC-20 代幣——sweep(address)

把方法選擇器與代幣合約地址拼接,地址左補零至 32 位元組:

01681a62
sweep(address) 的方法選擇器。
0000… (24)
24 個 0——地址左邊補 12 位元組。
4200…0042
代幣合約地址。示例:Optimism 上的 OP 代幣。
01681a620000000000000000000000004200000000000000000000000000000000000042

要 sweep 另一個 ERC-20,只需替換代幣地址(保留那 24 個 0 的補位)。

原生幣——sweepETH()

無參數。把合約裡全部原生餘額(ETH/BNB/…)轉給 owner:

0xd47f6877

Sweeper 方法

sweep(address)
0x01681a62
把指定 ERC-20 代幣的全部餘額轉給 owner(部署地址)。僅 owner 可呼叫。
sweepETH()
0xd47f6877
把全部原生餘額轉給 owner。僅 owner 可呼叫。
owner()
0x8da5cb5b
回傳 owner(建立合約的部署地址)。
execute(…)
0x0565bb67
僅 owner 可呼叫的通用底層呼叫——用於進階或非標準資產。

Sweeper 位元組碼(部署用)

步驟 4 部署時把它貼上到 Hex data。這是權威產物——部署出來的就是截圖中使用的同一個合約。

0x60a060405234801561000f575f80fd5b503360805260805161062461004e5f395f818160b30152818161010c015281816101d10152818161029d0152818161038b01526103cb01526106245ff3fe608060405260043610610041575f3560e01c806301681a621461004c5780630565bb671461006d5780638da5cb5b146100a2578063d47f6877146100ed575f80fd5b3661004857005b5f80fd5b348015610057575f80fd5b5061006b61006636600461049b565b610101565b005b348015610078575f80fd5b5061008c6100873660046104bb565b610290565b604051610099919061053b565b60405180910390f35b3480156100ad575f80fd5b506100d57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610099565b3480156100f8575f80fd5b5061006b610380565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101525760405162461bcd60e51b815260040161014990610586565b60405180910390fd5b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa158015610196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ba91906105a9565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390529192509083169063a9059cbb906044016020604051808303815f875af115801561022a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024e91906105c0565b61028c5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610149565b5050565b6060336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102da5760405162461bcd60e51b815260040161014990610586565b5f80866001600160a01b03168686866040516102f79291906105df565b5f6040518083038185875af1925050503d805f8114610331576040519150601f19603f3d011682016040523d82523d5f602084013e610336565b606091505b5091509150816103765760405162461bcd60e51b815260206004820152600b60248201526a195e1958c819985a5b195960aa1b6044820152606401610149565b9695505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103c85760405162461bcd60e51b815260040161014990610586565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316476040515f6040518083038185875af1925050503d805f8114610431576040519150601f19603f3d011682016040523d82523d5f602084013e610436565b606091505b505090508061047d5760405162461bcd60e51b8152602060048201526013602482015272195d1a081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610149565b50565b80356001600160a01b0381168114610496575f80fd5b919050565b5f602082840312156104ab575f80fd5b6104b482610480565b9392505050565b5f805f80606085870312156104ce575f80fd5b6104d785610480565b935060208501359250604085013567ffffffffffffffff808211156104fa575f80fd5b818701915087601f83011261050d575f80fd5b81358181111561051b575f80fd5b88602082850101111561052c575f80fd5b95989497505060200194505050565b5f6020808352835180828501525f5b818110156105665785810183015185820160400152820161054a565b505f604082860101526040601f19601f8301168501019250505092915050565b6020808252600990820152683737ba1037bbb732b960b91b604082015260600190565b5f602082840312156105b9575f80fd5b5051919050565b5f602082840312156105d0575f80fd5b815180151581146104b4575f80fd5b818382375f910190815291905056fea264697066735822122031b2c06cb6b8765e717b16767ac85aac2a4d53511b358bc0320bbb1e409a603b64736f6c63430008140033

Sweeper.sol(參考原碼)

用於核對的參考實作,Solidity 0.8.20。部署者成為不可變的 owner,只有 owner 能 sweep。

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
}

/// @title Sweeper
/// @notice Minimal single-key recovery contract. Deployed by the multisig's
///         deploy address so that it lands at the exact multisig address, then
///         used to move stuck assets to that deploy address (the owner).
contract Sweeper {
    address public immutable owner;

    constructor() {
        owner = msg.sender;
    }

    // Accept native coin (ETH/BNB/...).
    receive() external payable {}

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    /// @notice Send this contract's full balance of `token` to the owner.
    /// selector: sweep(address) = 0x01681a62
    function sweep(address token) external onlyOwner {
        uint256 bal = IERC20(token).balanceOf(address(this));
        require(IERC20(token).transfer(owner, bal), "transfer failed");
    }

    /// @notice Send this contract's full native balance to the owner.
    /// selector: sweepETH() = 0xd47f6877
    function sweepETH() external onlyOwner {
        (bool ok, ) = owner.call{value: address(this).balance}("");
        require(ok, "send failed");
    }

    /// @notice Owner-only generic call, for advanced / non-standard assets.
    /// selector: execute(address,uint256,bytes) = 0x0565bb67
    function execute(address target, uint256 value, bytes calldata data)
        external
        onlyOwner
        returns (bytes memory)
    {
        (bool ok, bytes memory ret) = target.call{value: value}(data);
        require(ok, "call failed");
        return ret;
    }
}

安全提示

把部署私鑰視為已洩露

一旦這個私鑰在聯網環境下用過,就請視為已洩露,之後不要再用它看守重要資產。

Ownbit · ownbit.io——非託管多簽與離線冷簽。本指南僅用於資產恢復。