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——非托管多签与离线冷签。本指南仅用于资产恢复。