Ownbit · 多簽恢復
你有一個 Ownbit 的 EVM 多簽,但資產被轉到了你本來沒計畫的鏈上,或者一條多簽無法操作的鏈上。資金並沒有遺失。具體怎麼做,取決於 Ownbit 是否在那條鏈上支援多簽。
Ownbit 多簽合約的地址是由它的 部署地址(deploy 地址)及該地址的 nonce 推導出來的,與鏈無關。因此同一個部署地址在任何 EVM 鏈上都會得到相同的合約地址。這是下面所有恢復方法的關鍵。
直接在那條鏈上再建立一次多簽即可。因為合約地址只取決於部署地址,在該鏈重新部署會把合約部署到你資金所在的同一個地址,資產隨即可以透過正常的多簽流程轉出。
部署完成後,在該鏈上打開錢包、像平時一樣把資產轉出即可。
例如 Optimism。這裡無法重建多簽,所以改為把一個小小的 Sweeper 合約部署到相同地址,再呼叫它把卡住的資產取出。請按下面的步驟操作。
把多簽的部署地址作為普通單私鑰錢包匯入,給它充一點 gas,再用它部署 Sweeper。由於地址由部署帳戶推導,Sweeper 會落在持有你卡住資金的那個合約地址上。然後呼叫 sweep() / sweepETH() 把資產全部拉回到部署地址。
部署地址在目標鏈上必須沒有發過任何轉出交易(nonce 未被使用),否則建立出來的地址會對不上。給它轉入(收款)是沒關係的。還需要該地址上有一點原生 gas(如 Optimism 上的 ETH)。
在 Ownbit 中,對該多簽打開 匯出私鑰,選擇帶有 (MS_DEPLOY_INDEX) 標記的地址——這就是部署你多簽合約的地址。顯示並複製它的私鑰。請離線保管,切勿貼上到任何網站。
注意:如果你的多簽地址不是由多簽錢包本身部署的,而是你手動選擇了某個熱錢包來部署的,那麼這裡要匯出的,必須是那個部署熱錢包的私鑰,而不是該多簽錢包的私鑰。

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

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

點 發送,選 ETH · Optimism。接收地址填 0x0——在 Ownbit 裡這表示「部署合約」。金額填 0。在確認頁打開進階選項,設定足夠的 Gas Limit(示例為 2,560,000),把下面的 Sweeper 位元組碼貼上到 Hex data。點發送。
這裡 Hex data 要填的位元組碼,請使用下文《Sweeper 位元組碼(部署用)》一節中的完整位元組碼。
在使用這個匯入的部署錢包期間,千萬不要隨意發送任何交易。每發送一筆交易都會消耗該地址的 nonce,一旦 nonce 被推進,就再也無法把合約部署到正確的多簽地址,資金將永遠無法取出。



在區塊瀏覽器上,該交易顯示為合約建立:To [0x…eb2 Created]。這個建立出的地址必須等於你的多簽地址。一致,說明 Sweeper 就落在你資金所在位置;不一致請停下——部署地址很可能在這條鏈上已經發過轉出交易了。
如果發現地址不一致,先在對應網路的區塊瀏覽器上查看你要恢復的那個多簽地址:找到建立該地址的合約建立交易,確認它當時使用的 nonce(例如 nonce = 3)。然後核對你匯入的部署私鑰,是否與當初部署多簽時用的私鑰一致。如果私鑰確實相同、只是當初部署用的是 nonce = 3,那麼建議你用同一個部署錢包按上面的流程重複部署,連續建立到第 3 次,直到得到與目標一致的地址——而不是隨便發交易去白白消耗 nonce。

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



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

一共兩個方法,在步驟 6 中任選一個填入 Hex data。
把方法選擇器與代幣合約地址拼接,地址左補零至 32 位元組:
01681a620000000000000000000000004200000000000000000000000000000000000042要 sweep 另一個 ERC-20,只需替換代幣地址(保留那 24 個 0 的補位)。
無參數。把合約裡全部原生餘額(ETH/BNB/…)轉給 owner:
0xd47f6877步驟 4 部署時把它貼上到 Hex data。這是權威產物——部署出來的就是截圖中使用的同一個合約。
0x60a060405234801561000f575f80fd5b503360805260805161062461004e5f395f818160b30152818161010c015281816101d10152818161029d0152818161038b01526103cb01526106245ff3fe608060405260043610610041575f3560e01c806301681a621461004c5780630565bb671461006d5780638da5cb5b146100a2578063d47f6877146100ed575f80fd5b3661004857005b5f80fd5b348015610057575f80fd5b5061006b61006636600461049b565b610101565b005b348015610078575f80fd5b5061008c6100873660046104bb565b610290565b604051610099919061053b565b60405180910390f35b3480156100ad575f80fd5b506100d57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610099565b3480156100f8575f80fd5b5061006b610380565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101525760405162461bcd60e51b815260040161014990610586565b60405180910390fd5b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa158015610196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ba91906105a9565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390529192509083169063a9059cbb906044016020604051808303815f875af115801561022a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024e91906105c0565b61028c5760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606401610149565b5050565b6060336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102da5760405162461bcd60e51b815260040161014990610586565b5f80866001600160a01b03168686866040516102f79291906105df565b5f6040518083038185875af1925050503d805f8114610331576040519150601f19603f3d011682016040523d82523d5f602084013e610336565b606091505b5091509150816103765760405162461bcd60e51b815260206004820152600b60248201526a195e1958c819985a5b195960aa1b6044820152606401610149565b9695505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103c85760405162461bcd60e51b815260040161014990610586565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316476040515f6040518083038185875af1925050503d805f8114610431576040519150601f19603f3d011682016040523d82523d5f602084013e610436565b606091505b505090508061047d5760405162461bcd60e51b8152602060048201526013602482015272195d1a081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610149565b50565b80356001600160a01b0381168114610496575f80fd5b919050565b5f602082840312156104ab575f80fd5b6104b482610480565b9392505050565b5f805f80606085870312156104ce575f80fd5b6104d785610480565b935060208501359250604085013567ffffffffffffffff808211156104fa575f80fd5b818701915087601f83011261050d575f80fd5b81358181111561051b575f80fd5b88602082850101111561052c575f80fd5b95989497505060200194505050565b5f6020808352835180828501525f5b818110156105665785810183015185820160400152820161054a565b505f604082860101526040601f19601f8301168501019250505092915050565b6020808252600990820152683737ba1037bbb732b960b91b604082015260600190565b5f602082840312156105b9575f80fd5b5051919050565b5f602082840312156105d0575f80fd5b815180151581146104b4575f80fd5b818382375f910190815291905056fea264697066735822122031b2c06cb6b8765e717b16767ac85aac2a4d53511b358bc0320bbb1e409a603b64736f6c63430008140033用於核對的參考實作,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;
}
}一旦這個私鑰在聯網環境下用過,就請視為已洩露,之後不要再用它看守重要資產。