文件 1 的 15:Address.sol
pragma solidity ^0.7.0;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 15:ChannelFactory.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/utils/Create2.sol";
import "./interfaces/IChannelFactory.sol";
import "./interfaces/IVectorChannel.sol";
import "./lib/LibAsset.sol";
import "./lib/LibERC20.sol";
contract ChannelFactory is IChannelFactory {
bytes private constant proxyCreationCodePrefix =
hex"3d602d80600a3d3981f3_363d3d373d3d3d363d73";
bytes private constant proxyCreationCodeSuffix =
hex"5af43d82803e903d91602b57fd5bf3";
bytes32 private creationCodeHash;
address private immutable mastercopy;
uint256 private immutable chainId;
constructor(address _mastercopy, uint256 _chainId) {
mastercopy = _mastercopy;
chainId = _chainId;
creationCodeHash = keccak256(_getProxyCreationCode(_mastercopy));
}
function getMastercopy() external view override returns (address) {
return mastercopy;
}
function getChainId() public view override returns (uint256 _chainId) {
uint256 chain = chainId;
if (chain == 0) {
assembly {
_chainId := chainid()
}
} else {
_chainId = chain;
}
}
function getStoredChainId() external view override returns (uint256) {
return chainId;
}
function getProxyCreationCode()
public
view
override
returns (bytes memory)
{
return _getProxyCreationCode(mastercopy);
}
function getChannelAddress(address alice, address bob)
external
view
override
returns (address)
{
return
Create2.computeAddress(
generateSalt(alice, bob),
creationCodeHash
);
}
function createChannel(address alice, address bob)
public
override
returns (address channel)
{
channel = deployChannelProxy(alice, bob);
IVectorChannel(channel).setup(alice, bob);
emit ChannelCreation(channel);
}
function createChannelAndDepositAlice(
address alice,
address bob,
address assetId,
uint256 amount
) external payable override returns (address channel) {
channel = createChannel(alice, bob);
if (!LibAsset.isEther(assetId)) {
require(
LibERC20.transferFrom(
assetId,
msg.sender,
address(this),
amount
),
"ChannelFactory: ERC20_TRANSFER_FAILED"
);
require(
LibERC20.approve(assetId, address(channel), amount),
"ChannelFactory: ERC20_APPROVE_FAILED"
);
}
IVectorChannel(channel).depositAlice{value: msg.value}(assetId, amount);
}
function _getProxyCreationCode(address _mastercopy) internal pure returns (bytes memory) {
return abi.encodePacked(
proxyCreationCodePrefix,
_mastercopy,
proxyCreationCodeSuffix
);
}
function deployChannelProxy(address alice, address bob)
internal
returns (address)
{
bytes32 salt = generateSalt(alice, bob);
return Create2.deploy(0, salt, getProxyCreationCode());
}
function generateSalt(address alice, address bob)
internal
view
returns (bytes32)
{
return keccak256(abi.encodePacked(alice, bob, getChainId()));
}
}
文件 3 的 15:Create2.sol
pragma solidity ^0.7.0;
library Create2 {
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address) {
address addr;
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
return addr;
}
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address) {
bytes32 _data = keccak256(
abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
);
return address(uint256(_data));
}
}
文件 4 的 15:ICMCAdjudicator.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
import "./Types.sol";
interface ICMCAdjudicator {
struct CoreChannelState {
address channelAddress;
address alice;
address bob;
address[] assetIds;
Balance[] balances;
uint256[] processedDepositsA;
uint256[] processedDepositsB;
uint256[] defundNonces;
uint256 timeout;
uint256 nonce;
bytes32 merkleRoot;
}
struct CoreTransferState {
address channelAddress;
bytes32 transferId;
address transferDefinition;
address initiator;
address responder;
address assetId;
Balance balance;
uint256 transferTimeout;
bytes32 initialStateHash;
}
struct ChannelDispute {
bytes32 channelStateHash;
uint256 nonce;
bytes32 merkleRoot;
uint256 consensusExpiry;
uint256 defundExpiry;
}
struct TransferDispute {
bytes32 transferStateHash;
uint256 transferDisputeExpiry;
bool isDefunded;
}
event ChannelDisputed(
address disputer,
CoreChannelState state,
ChannelDispute dispute
);
event ChannelDefunded(
address defunder,
CoreChannelState state,
ChannelDispute dispute,
address[] assetIds
);
event TransferDisputed(
address disputer,
CoreTransferState state,
TransferDispute dispute
);
event TransferDefunded(
address defunder,
CoreTransferState state,
TransferDispute dispute,
bytes encodedInitialState,
bytes encodedResolver,
Balance balance
);
function getChannelDispute() external view returns (ChannelDispute memory);
function getDefundNonce(address assetId) external view returns (uint256);
function getTransferDispute(bytes32 transferId)
external
view
returns (TransferDispute memory);
function disputeChannel(
CoreChannelState calldata ccs,
bytes calldata aliceSignature,
bytes calldata bobSignature
) external;
function defundChannel(
CoreChannelState calldata ccs,
address[] calldata assetIds,
uint256[] calldata indices
) external;
function disputeTransfer(
CoreTransferState calldata cts,
bytes32[] calldata merkleProofData
) external;
function defundTransfer(
CoreTransferState calldata cts,
bytes calldata encodedInitialTransferState,
bytes calldata encodedTransferResolver,
bytes calldata responderSignature
) external;
}
文件 5 的 15:ICMCAsset.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
interface ICMCAsset {
function getTotalTransferred(address assetId)
external
view
returns (uint256);
function getExitableAmount(address assetId, address owner)
external
view
returns (uint256);
function exit(
address assetId,
address owner,
address payable recipient
) external;
}
文件 6 的 15:ICMCCore.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
interface ICMCCore {
function setup(address _alice, address _bob) external;
function getAlice() external view returns (address);
function getBob() external view returns (address);
}
文件 7 的 15:ICMCDeposit.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
interface ICMCDeposit {
event AliceDeposited(address assetId, uint256 amount);
function getTotalDepositsAlice(address assetId)
external
view
returns (uint256);
function getTotalDepositsBob(address assetId)
external
view
returns (uint256);
function depositAlice(address assetId, uint256 amount) external payable;
}
文件 8 的 15:ICMCWithdraw.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
struct WithdrawData {
address channelAddress;
address assetId;
address payable recipient;
uint256 amount;
uint256 nonce;
address callTo;
bytes callData;
}
interface ICMCWithdraw {
function getWithdrawalTransactionRecord(WithdrawData calldata wd)
external
view
returns (bool);
function withdraw(
WithdrawData calldata wd,
bytes calldata aliceSignature,
bytes calldata bobSignature
) external;
}
文件 9 的 15:IChannelFactory.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
interface IChannelFactory {
event ChannelCreation(address channel);
function getMastercopy() external view returns (address);
function getChainId() external view returns (uint256);
function getStoredChainId() external view returns (uint256);
function getProxyCreationCode() external view returns (bytes memory);
function getChannelAddress(address alice, address bob)
external
view
returns (address);
function createChannel(address alice, address bob)
external
returns (address);
function createChannelAndDepositAlice(
address alice,
address bob,
address assetId,
uint256 amount
) external payable returns (address);
}
文件 10 的 15:IERC20.sol
pragma solidity ^0.7.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 11 的 15:IVectorChannel.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
import "./ICMCCore.sol";
import "./ICMCAsset.sol";
import "./ICMCDeposit.sol";
import "./ICMCWithdraw.sol";
import "./ICMCAdjudicator.sol";
interface IVectorChannel is
ICMCCore,
ICMCAsset,
ICMCDeposit,
ICMCWithdraw,
ICMCAdjudicator
{}
文件 12 的 15:LibAsset.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
import "./LibERC20.sol";
import "./LibUtils.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
library LibAsset {
address constant ETHER_ASSETID = address(0);
function isEther(address assetId) internal pure returns (bool) {
return assetId == ETHER_ASSETID;
}
function getOwnBalance(address assetId) internal view returns (uint256) {
return
isEther(assetId)
? address(this).balance
: IERC20(assetId).balanceOf(address(this));
}
function transferEther(address payable recipient, uint256 amount)
internal
returns (bool)
{
(bool success, bytes memory returnData) =
recipient.call{value: amount}("");
LibUtils.revertIfCallFailed(success, returnData);
return true;
}
function transferERC20(
address assetId,
address recipient,
uint256 amount
) internal returns (bool) {
return LibERC20.transfer(assetId, recipient, amount);
}
function unregisteredTransfer(
address assetId,
address payable recipient,
uint256 amount
) internal returns (bool) {
return
isEther(assetId)
? transferEther(recipient, amount)
: transferERC20(assetId, recipient, amount);
}
}
文件 13 的 15:LibERC20.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
import "./LibUtils.sol";
import "@openzeppelin/contracts/utils/Address.sol";
library LibERC20 {
function wrapCall(address assetId, bytes memory callData)
internal
returns (bool)
{
require(Address.isContract(assetId), "LibERC20: NO_CODE");
(bool success, bytes memory returnData) = assetId.call(callData);
LibUtils.revertIfCallFailed(success, returnData);
return returnData.length == 0 || abi.decode(returnData, (bool));
}
function approve(
address assetId,
address spender,
uint256 amount
) internal returns (bool) {
return
wrapCall(
assetId,
abi.encodeWithSignature(
"approve(address,uint256)",
spender,
amount
)
);
}
function transferFrom(
address assetId,
address sender,
address recipient,
uint256 amount
) internal returns (bool) {
return
wrapCall(
assetId,
abi.encodeWithSignature(
"transferFrom(address,address,uint256)",
sender,
recipient,
amount
)
);
}
function transfer(
address assetId,
address recipient,
uint256 amount
) internal returns (bool) {
return
wrapCall(
assetId,
abi.encodeWithSignature(
"transfer(address,uint256)",
recipient,
amount
)
);
}
}
文件 14 的 15:LibUtils.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
library LibUtils {
function revertIfCallFailed(bool success, bytes memory returnData)
internal
pure
{
if (!success) {
assembly {
revert(add(returnData, 0x20), mload(returnData))
}
}
}
}
文件 15 的 15:Types.sol
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;
struct Balance {
uint256[2] amount;
address payable[2] to;
}
{
"compilationTarget": {
"src.sol/ChannelFactory.sol": "ChannelFactory"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_mastercopy","type":"address"},{"internalType":"uint256","name":"_chainId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"channel","type":"address"}],"name":"ChannelCreation","type":"event"},{"inputs":[{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"}],"name":"createChannel","outputs":[{"internalType":"address","name":"channel","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"createChannelAndDepositAlice","outputs":[{"internalType":"address","name":"channel","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"}],"name":"getChannelAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMastercopy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProxyCreationCode","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStoredChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]