编译器
0.4.24+commit.e67f0147
文件 1 的 19:BimodalLib.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./SafeMathLib256.sol";
library BimodalLib {
using SafeMathLib256 for uint256;
enum ChallengeType {NONE, STATE_UPDATE, TRANSFER_DELIVERY, SWAP_ENACTMENT}
struct AmountAggregate {
uint256 eon;
uint256 amount;
}
struct Checkpoint {
uint256 eonNumber;
bytes32 merkleRoot;
uint256 liveChallenges;
}
struct Wallet {
AmountAggregate[3] depositsKept;
Withdrawal[] withdrawals;
bool recovered;
}
struct Withdrawal {
uint256 eon;
uint256 amount;
}
struct Challenge {
ChallengeType challengeType;
uint256 block;
uint256 initialStateEon;
uint256 initialStateBalance;
uint256 deltaHighestSpendings;
uint256 deltaHighestGains;
uint256 finalStateBalance;
uint256 deliveredTxNonce;
uint64 trailIdentifier;
}
enum Operation {DEPOSIT, WITHDRAWAL, CANCELLATION}
struct Ledger {
uint8 EONS_KEPT;
uint8 DEPOSITS_KEPT;
uint256 MIN_CHALLENGE_GAS_COST;
uint256 BLOCKS_PER_EON;
uint256 BLOCKS_PER_EPOCH;
uint256 EXTENDED_BLOCKS_PER_EPOCH;
uint256 genesis;
address operator;
Checkpoint[5] checkpoints;
bytes32[5] parentChainAccumulator;
uint256 lastSubmissionEon;
mapping(address => mapping(address => mapping(address => Challenge))) challengeBook;
mapping(address => mapping(address => Wallet)) walletBook;
mapping(address => AmountAggregate[5]) deposits;
mapping(address => AmountAggregate[5]) pendingWithdrawals;
mapping(address => AmountAggregate[5]) confirmedWithdrawals;
mapping(address => uint64) tokenToTrail;
address[] trailToToken;
}
function init(
Ledger storage self,
uint256 blocksPerEon,
address operator
) public {
self.BLOCKS_PER_EON = blocksPerEon;
self.BLOCKS_PER_EPOCH = self.BLOCKS_PER_EON.div(4);
self.EXTENDED_BLOCKS_PER_EPOCH = self.BLOCKS_PER_EON.div(3);
self.EONS_KEPT = 5;
self.DEPOSITS_KEPT = 3;
self.MIN_CHALLENGE_GAS_COST = 0.005 szabo;
self.operator = operator;
self.genesis = block.number;
}
function currentEon(Ledger storage self) public view returns (uint256) {
return block.number.sub(self.genesis).div(self.BLOCKS_PER_EON).add(1);
}
function currentEra(Ledger storage self) public view returns (uint256) {
return block.number.sub(self.genesis).mod(self.BLOCKS_PER_EON);
}
function appendOperationToEonAccumulator(
Ledger storage self,
uint256 eon,
ERC20 token,
address participant,
Operation operation,
uint256 value
) public {
self.parentChainAccumulator[eon.mod(self.EONS_KEPT)] = keccak256(
abi.encodePacked(
self.parentChainAccumulator[eon.mod(self.EONS_KEPT)],
eon,
token,
participant,
operation,
value
)
);
}
function getPendingWithdrawalsAtEon(
Ledger storage self,
ERC20 token,
uint256 eon
) public view returns (uint256) {
uint256 lastAggregateEon = 0;
for (uint256 i = 0; i < self.EONS_KEPT; i++) {
AmountAggregate storage currentAggregate = self
.pendingWithdrawals[token][eon.mod(self.EONS_KEPT)];
if (currentAggregate.eon == eon) {
return currentAggregate.amount;
} else if (
currentAggregate.eon > lastAggregateEon &&
currentAggregate.eon < eon
) {
lastAggregateEon = currentAggregate.eon;
}
if (eon == 0) {
break;
}
eon = eon.sub(1);
}
if (lastAggregateEon == 0) {
return 0;
}
return
self.pendingWithdrawals[token][lastAggregateEon.mod(self.EONS_KEPT)]
.amount;
}
function addToRunningPendingWithdrawals(
Ledger storage self,
ERC20 token,
uint256 eon,
uint256 value
) public {
AmountAggregate storage aggregate = self.pendingWithdrawals[token][eon
.mod(self.EONS_KEPT)];
if (aggregate.eon < eon) {
aggregate.amount = getPendingWithdrawalsAtEon(
self,
token,
eon.sub(1)
)
.add(value);
aggregate.eon = eon;
} else {
aggregate.amount = aggregate.amount.add(value);
}
}
function deductFromRunningPendingWithdrawals(
Ledger storage self,
ERC20 token,
uint256 eon,
uint256 latestEon,
uint256 value
) public {
for (uint256 i = 0; i < self.EONS_KEPT; i++) {
uint256 targetEon = eon.add(i);
AmountAggregate storage aggregate = self
.pendingWithdrawals[token][targetEon.mod(self.EONS_KEPT)];
if (targetEon > latestEon) {
break;
} else if (aggregate.eon < targetEon) {
aggregate.eon = targetEon;
aggregate.amount = getPendingWithdrawalsAtEon(
self,
token,
targetEon.sub(1)
);
}
}
for (i = 0; i < self.EONS_KEPT; i++) {
targetEon = eon.add(i);
aggregate = self.pendingWithdrawals[token][targetEon.mod(
self.EONS_KEPT
)];
if (targetEon > latestEon) {
break;
} else if (aggregate.eon < targetEon) {
revert("X");
} else {
aggregate.amount = aggregate.amount.sub(value);
}
}
}
function getLiveChallenges(Ledger storage self, uint256 eon)
public
view
returns (uint256)
{
Checkpoint storage checkpoint = self.checkpoints[eon.mod(
self.EONS_KEPT
)];
if (checkpoint.eonNumber != eon) {
return 0;
}
return checkpoint.liveChallenges;
}
function getOrCreateCheckpoint(
Ledger storage self,
uint256 targetEon,
uint256 latestEon
) public returns (Checkpoint storage checkpoint) {
require(
latestEon < targetEon.add(self.EONS_KEPT) && targetEon <= latestEon
);
uint256 index = targetEon.mod(self.EONS_KEPT);
checkpoint = self.checkpoints[index];
if (checkpoint.eonNumber != targetEon) {
checkpoint.eonNumber = targetEon;
checkpoint.merkleRoot = bytes32(0);
checkpoint.liveChallenges = 0;
}
return checkpoint;
}
function getWalletPendingWithdrawalAmountAtEon(
Ledger storage self,
ERC20 token,
address holder,
uint256 eon
) public view returns (uint256 amount) {
amount = 0;
Wallet storage accountingEntry = self.walletBook[token][holder];
Withdrawal[] storage withdrawals = accountingEntry.withdrawals;
for (uint32 i = 0; i < withdrawals.length; i++) {
Withdrawal storage withdrawal = withdrawals[i];
if (withdrawal.eon == eon) {
amount = amount.add(withdrawal.amount);
} else if (withdrawal.eon > eon) {
break;
}
}
}
function getCurrentEonDepositsWithdrawals(
Ledger storage self,
ERC20 token,
address holder
)
public
view
returns (uint256 currentEonDeposits, uint256 currentEonWithdrawals)
{
currentEonDeposits = 0;
currentEonWithdrawals = 0;
Wallet storage accountingEntry = self.walletBook[token][holder];
Challenge storage challengeEntry = self
.challengeBook[token][holder][holder];
AmountAggregate storage depositEntry = accountingEntry
.depositsKept[challengeEntry.initialStateEon.mod(
self.DEPOSITS_KEPT
)];
if (depositEntry.eon == challengeEntry.initialStateEon) {
currentEonDeposits = currentEonDeposits.add(depositEntry.amount);
}
currentEonWithdrawals = getWalletPendingWithdrawalAmountAtEon(
self,
token,
holder,
challengeEntry.initialStateEon
);
return (currentEonDeposits, currentEonWithdrawals);
}
function addToAggregate(
AmountAggregate storage aggregate,
uint256 eon,
uint256 value
) public {
if (eon > aggregate.eon) {
aggregate.eon = eon;
aggregate.amount = value;
} else {
aggregate.amount = aggregate.amount.add(value);
}
}
function clearAggregate(AmountAggregate storage aggregate) public {
aggregate.eon = 0;
aggregate.amount = 0;
}
function signedMessageECRECOVER(
bytes32 message,
bytes32 r,
bytes32 s,
uint8 v
) public pure returns (address) {
return
ecrecover(
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(
abi.encodePacked(
"\x19Liquidity.Network Authorization:\n32",
message
)
)
)
),
v,
r,
s
);
}
}
文件 2 的 19:BimodalProxy.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./BimodalLib.sol";
import "./SafeMathLib256.sol";
contract BimodalProxy {
using SafeMathLib256 for uint256;
using BimodalLib for BimodalLib.Ledger;
event CheckpointSubmission(uint256 indexed eon, bytes32 merkleRoot);
event Deposit(
address indexed token,
address indexed recipient,
uint256 amount
);
event WithdrawalRequest(
address indexed token,
address indexed requestor,
uint256 amount
);
event WithdrawalConfirmation(
address indexed token,
address indexed requestor,
uint256 amount
);
event ChallengeIssued(
address indexed token,
address indexed recipient,
address indexed sender
);
event StateUpdate(
address indexed token,
address indexed account,
uint256 indexed eon,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
bytes32 activeStateChecksum,
bytes32 passiveChecksum,
bytes32 r,
bytes32 s,
uint8 v
);
BimodalLib.Ledger internal ledger;
constructor(uint256 blocksPerEon, address operator) public {
ledger.init(blocksPerEon, operator);
}
modifier onlyOperator() {
require(msg.sender == ledger.operator);
_;
}
modifier onlyWhenContractUnpunished() {
require(
!hasOutstandingChallenges() && !hasMissedCheckpointSubmission(),
"p"
);
_;
}
function getClientContractStateVariables(ERC20 token, address holder)
public
view
returns (
uint256 latestCheckpointEonNumber,
bytes32[5] latestCheckpointsMerkleRoots,
uint256[5] latestCheckpointsLiveChallenges,
uint256 currentEonDeposits,
uint256 previousEonDeposits,
uint256 secondPreviousEonDeposits,
uint256[2][] pendingWithdrawals,
uint256 holderBalance
)
{
latestCheckpointEonNumber = ledger.lastSubmissionEon;
for (
uint32 i = 0;
i < ledger.EONS_KEPT && i < ledger.currentEon();
i++
) {
BimodalLib.Checkpoint storage checkpoint = ledger.checkpoints[ledger
.lastSubmissionEon
.sub(i)
.mod(ledger.EONS_KEPT)];
latestCheckpointsMerkleRoots[i] = checkpoint.merkleRoot;
latestCheckpointsLiveChallenges[i] = checkpoint.liveChallenges;
}
holderBalance = ledger.currentEon();
currentEonDeposits = getDepositsAtEon(token, holder, holderBalance);
if (holderBalance > 1) {
previousEonDeposits = getDepositsAtEon(
token,
holder,
holderBalance - 1
);
}
if (holderBalance > 2) {
secondPreviousEonDeposits = getDepositsAtEon(
token,
holder,
holderBalance - 2
);
}
BimodalLib.Wallet storage wallet = ledger.walletBook[token][holder];
pendingWithdrawals = new uint256[2][](wallet.withdrawals.length);
for (i = 0; i < wallet.withdrawals.length; i++) {
BimodalLib.Withdrawal storage withdrawal = wallet.withdrawals[i];
pendingWithdrawals[i] = [withdrawal.eon, withdrawal.amount];
}
holderBalance = token != address(this)
? token.balanceOf(holder)
: holder.balance;
}
function getServerContractStateVariables()
public
view
returns (
bytes32 parentChainAccumulator,
uint256 lastSubmissionEon,
bytes32 lastCheckpointRoot,
bool isCheckpointSubmitted,
bool missedCheckpointSubmission,
uint256 liveChallenges
)
{
uint256 currentEon = ledger.currentEon();
parentChainAccumulator = getParentChainAccumulatorAtSlot(
uint8(currentEon.mod(ledger.EONS_KEPT))
);
BimodalLib.Checkpoint storage lastCheckpoint = ledger.checkpoints[ledger
.lastSubmissionEon
.mod(ledger.EONS_KEPT)];
lastSubmissionEon = ledger.lastSubmissionEon;
lastCheckpointRoot = lastCheckpoint.merkleRoot;
isCheckpointSubmitted = lastSubmissionEon == currentEon;
missedCheckpointSubmission = hasMissedCheckpointSubmission();
liveChallenges = getLiveChallenges(currentEon);
}
function getServerContractLedgerStateVariables(
uint256 eonNumber,
ERC20 token
)
public
view
returns (
uint256 pendingWithdrawals,
uint256 confirmedWithdrawals,
uint256 deposits,
uint256 totalBalance
)
{
uint8 eonSlot = uint8(eonNumber.mod(ledger.EONS_KEPT));
uint256 targetEon = 0;
(targetEon, pendingWithdrawals) = getPendingWithdrawalsAtSlot(
token,
eonSlot
);
if (targetEon != eonNumber) {
pendingWithdrawals = 0;
}
(targetEon, confirmedWithdrawals) = getConfirmedWithdrawalsAtSlot(
token,
eonSlot
);
if (targetEon != eonNumber) {
confirmedWithdrawals = 0;
}
(targetEon, deposits) = getDepositsAtSlot(token, eonSlot);
if (targetEon != eonNumber) {
deposits = 0;
}
totalBalance = token != address(this)
? token.balanceOf(this)
: address(this).balance;
}
function hasOutstandingChallenges() public view returns (bool) {
return
ledger.getLiveChallenges(ledger.currentEon().sub(1)) > 0 &&
ledger.currentEra() > ledger.BLOCKS_PER_EPOCH;
}
function hasMissedCheckpointSubmission() public view returns (bool) {
return ledger.currentEon().sub(ledger.lastSubmissionEon) > 1;
}
function getCheckpointAtSlot(uint8 slot)
public
view
returns (
uint256,
bytes32,
uint256
)
{
BimodalLib.Checkpoint storage checkpoint = ledger.checkpoints[slot];
return (
checkpoint.eonNumber,
checkpoint.merkleRoot,
checkpoint.liveChallenges
);
}
function getParentChainAccumulatorAtSlot(uint8 slot)
public
view
returns (bytes32)
{
return ledger.parentChainAccumulator[slot];
}
function getChallenge(
ERC20 token,
address sender,
address recipient
)
public
view
returns (
BimodalLib.ChallengeType,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint64
)
{
BimodalLib.Challenge storage challenge = ledger
.challengeBook[token][recipient][sender];
return (
challenge.challengeType,
challenge.block,
challenge.initialStateEon,
challenge.initialStateBalance,
challenge.deltaHighestSpendings,
challenge.deltaHighestGains,
challenge.finalStateBalance,
challenge.deliveredTxNonce,
challenge.trailIdentifier
);
}
function getIsWalletRecovered(ERC20 token, address holder)
public
view
returns (bool)
{
BimodalLib.Wallet storage wallet = ledger.walletBook[token][holder];
return (wallet.recovered);
}
function getDepositsAtEon(
ERC20 token,
address addr,
uint256 eon
) public view returns (uint256) {
(
uint256 aggregateEon,
uint256 aggregateAmount
) = getWalletDepositAggregateAtSlot(
token,
addr,
uint8(eon.mod(ledger.DEPOSITS_KEPT))
);
return aggregateEon == eon ? aggregateAmount : 0;
}
function getDepositsAtSlot(ERC20 token, uint8 slot)
public
view
returns (uint256, uint256)
{
BimodalLib.AmountAggregate storage aggregate = ledger
.deposits[token][slot];
return (aggregate.eon, aggregate.amount);
}
function getWalletDepositAggregateAtSlot(
ERC20 token,
address addr,
uint8 slot
) public view returns (uint256, uint256) {
BimodalLib.AmountAggregate memory deposit = ledger
.walletBook[token][addr]
.depositsKept[slot];
return (deposit.eon, deposit.amount);
}
function getPendingWithdrawalsAtEon(ERC20 token, uint256 eon)
public
view
returns (uint256)
{
return ledger.getPendingWithdrawalsAtEon(token, eon);
}
function getPendingWithdrawalsAtSlot(ERC20 token, uint8 slot)
public
view
returns (uint256, uint256)
{
BimodalLib.AmountAggregate storage aggregate = ledger
.pendingWithdrawals[token][slot];
return (aggregate.eon, aggregate.amount);
}
function getConfirmedWithdrawalsAtSlot(ERC20 token, uint8 slot)
public
view
returns (uint256, uint256)
{
BimodalLib.AmountAggregate storage aggregate = ledger
.confirmedWithdrawals[token][slot];
return (aggregate.eon, aggregate.amount);
}
function getWalletPendingWithdrawalAmountAtEon(
ERC20 token,
address holder,
uint256 eon
) public view returns (uint256) {
return ledger.getWalletPendingWithdrawalAmountAtEon(token, holder, eon);
}
function getTokenTrail(ERC20 token) public view returns (uint64) {
return ledger.tokenToTrail[token];
}
function getTokenAtTrail(uint64 trail) public view returns (address) {
return ledger.trailToToken[trail];
}
function getCurrentEonDepositsWithdrawals(ERC20 token, address holder)
public
view
returns (uint256 currentEonDeposits, uint256 currentEonWithdrawals)
{
return ledger.getCurrentEonDepositsWithdrawals(token, holder);
}
function EONS_KEPT()
public
view
returns (
uint8
)
{
return ledger.EONS_KEPT;
}
function DEPOSITS_KEPT()
public
view
returns (
uint8
)
{
return ledger.DEPOSITS_KEPT;
}
function MIN_CHALLENGE_GAS_COST()
public
view
returns (
uint256
)
{
return ledger.MIN_CHALLENGE_GAS_COST;
}
function BLOCKS_PER_EON()
public
view
returns (
uint256
)
{
return ledger.BLOCKS_PER_EON;
}
function BLOCKS_PER_EPOCH()
public
view
returns (
uint256
)
{
return ledger.BLOCKS_PER_EPOCH;
}
function EXTENDED_BLOCKS_PER_EPOCH()
public
view
returns (
uint256
)
{
return ledger.EXTENDED_BLOCKS_PER_EPOCH;
}
function genesis() public view returns (uint256) {
return ledger.genesis;
}
function operator() public view returns (address) {
return ledger.operator;
}
function lastSubmissionEon() public view returns (uint256) {
return ledger.lastSubmissionEon;
}
function currentEon() public view returns (uint256) {
return ledger.currentEon();
}
function currentEra() public view returns (uint256) {
return ledger.currentEra();
}
function getLiveChallenges(uint256 eon) public view returns (uint256) {
BimodalLib.Checkpoint storage checkpoint = ledger.checkpoints[eon.mod(
ledger.EONS_KEPT
)];
if (checkpoint.eonNumber != eon) {
return 0;
}
return checkpoint.liveChallenges;
}
function signedMessageECRECOVER(
bytes32 message,
bytes32 r,
bytes32 s,
uint8 v
) public pure returns (address) {
return BimodalLib.signedMessageECRECOVER(message, r, s, v);
}
}
文件 3 的 19:ChallengeLib.sol
pragma solidity ^0.4.24;
import "./BimodalLib.sol";
import "./MerkleVerifier.sol";
import "./SafeMathLib32.sol";
import "./SafeMathLib256.sol";
library ChallengeLib {
using SafeMathLib256 for uint256;
using SafeMathLib32 for uint32;
using BimodalLib for BimodalLib.Ledger;
event ChallengeIssued(
address indexed token,
address indexed recipient,
address indexed sender
);
event StateUpdate(
address indexed token,
address indexed account,
uint256 indexed eon,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
bytes32 activeStateChecksum,
bytes32 passiveChecksum,
bytes32 r,
bytes32 s,
uint8 v
);
function verifyProofOfExclusiveAccountBalanceAllotment(
BimodalLib.Ledger storage ledger,
ERC20 token,
address holder,
bytes32[2] activeStateChecksum_passiveTransfersRoot,
uint64 trail,
uint256[3] eonPassiveMark,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2] LR
) public view returns (bool) {
BimodalLib.Checkpoint memory checkpoint = ledger
.checkpoints[eonPassiveMark[0].mod(ledger.EONS_KEPT)];
require(eonPassiveMark[0] == checkpoint.eonNumber, "r");
activeStateChecksum_passiveTransfersRoot[0] = keccak256(
abi.encodePacked(
keccak256(abi.encodePacked(address(this))),
keccak256(abi.encodePacked(token)),
keccak256(abi.encodePacked(holder)),
keccak256(
abi.encodePacked(
activeStateChecksum_passiveTransfersRoot[1],
eonPassiveMark[1],
eonPassiveMark[2]
)
),
activeStateChecksum_passiveTransfersRoot[0]
)
);
activeStateChecksum_passiveTransfersRoot[0] = keccak256(
abi.encodePacked(
LR[0],
activeStateChecksum_passiveTransfersRoot[0],
LR[1]
)
);
uint64 tokenTrail = ledger.tokenToTrail[token];
LR[0] = MerkleVerifier.verifyProofOfExclusiveBalanceAllotment(
trail,
tokenTrail,
activeStateChecksum_passiveTransfersRoot[0],
checkpoint.merkleRoot,
allotmentChain,
membershipChain,
values,
LR
);
LR[1] = address(this).balance;
if (token != address(this)) {
require(tokenTrail != 0, "t");
LR[1] = token.balanceOf(this);
}
for (tokenTrail = 0; tokenTrail < ledger.EONS_KEPT; tokenTrail++) {
if (
ledger.confirmedWithdrawals[token][tokenTrail].eon >=
eonPassiveMark[0]
) {
LR[1] = LR[1].add(
ledger.confirmedWithdrawals[token][tokenTrail].amount
);
}
}
for (tokenTrail = 0; tokenTrail < ledger.EONS_KEPT; tokenTrail++) {
if (ledger.deposits[token][tokenTrail].eon >= eonPassiveMark[0]) {
LR[1] = LR[1].sub(ledger.deposits[token][tokenTrail].amount);
}
}
LR[1] = LR[1].sub(
ledger.getPendingWithdrawalsAtEon(token, eonPassiveMark[0].sub(1))
);
require(LR[0] <= LR[1], "b");
return true;
}
function verifyProofOfActiveStateUpdateAgreement(
ERC20 token,
address holder,
uint64 trail,
uint256 eon,
bytes32 txSetRoot,
uint256[2] deltas,
address attester,
bytes32 r,
bytes32 s,
uint8 v
) public view returns (bytes32 checksum) {
checksum = MerkleVerifier.activeStateUpdateChecksum(
token,
holder,
trail,
eon,
txSetRoot,
deltas
);
require(
attester == BimodalLib.signedMessageECRECOVER(checksum, r, s, v),
"A"
);
}
function verifyWithdrawalAuthorization(
ERC20 token,
address holder,
uint256 expiry,
uint256 amount,
address attester,
bytes32 r,
bytes32 s,
uint8 v
) public view returns (bool) {
bytes32 checksum = keccak256(
abi.encodePacked(
keccak256(abi.encodePacked(address(this))),
keccak256(abi.encodePacked(token)),
keccak256(abi.encodePacked(holder)),
expiry,
amount
)
);
require(
attester == BimodalLib.signedMessageECRECOVER(checksum, r, s, v),
"a"
);
return true;
}
function markChallengeLive(
BimodalLib.Ledger storage ledger,
ERC20 token,
address recipient,
address sender
) private {
require(ledger.currentEra() > ledger.BLOCKS_PER_EPOCH);
uint256 eon = ledger.currentEon();
BimodalLib.Checkpoint storage checkpoint = ledger.getOrCreateCheckpoint(
eon,
eon
);
checkpoint.liveChallenges = checkpoint.liveChallenges.add(1);
emit ChallengeIssued(token, recipient, sender);
}
function clearChallenge(
BimodalLib.Ledger storage ledger,
BimodalLib.Challenge storage challenge
) private {
BimodalLib.Checkpoint storage checkpoint = ledger.getOrCreateCheckpoint(
challenge.initialStateEon.add(1),
ledger.currentEon()
);
checkpoint.liveChallenges = checkpoint.liveChallenges.sub(1);
challenge.challengeType = BimodalLib.ChallengeType.NONE;
challenge.block = 0;
challenge.initialStateBalance = 0;
challenge.deltaHighestSpendings = 0;
challenge.deltaHighestGains = 0;
challenge.finalStateBalance = 0;
challenge.deliveredTxNonce = 0;
challenge.trailIdentifier = 0;
}
function markChallengeAnswered(
BimodalLib.Ledger storage ledger,
BimodalLib.Challenge storage challenge
) private {
uint256 eon = ledger.currentEon();
require(
challenge.challengeType != BimodalLib.ChallengeType.NONE &&
block.number.sub(challenge.block) < ledger.BLOCKS_PER_EPOCH &&
(challenge.initialStateEon == eon.sub(1) ||
(challenge.initialStateEon == eon.sub(2) &&
ledger.currentEra() < ledger.BLOCKS_PER_EPOCH))
);
clearChallenge(ledger, challenge);
}
function initStateUpdateChallenge(
BimodalLib.Ledger storage ledger,
ERC20 token,
uint256 owed,
uint256[2] spentGained,
uint64 trail
) private {
BimodalLib.Challenge storage challengeEntry = ledger
.challengeBook[token][msg.sender][msg.sender];
require(challengeEntry.challengeType == BimodalLib.ChallengeType.NONE);
require(challengeEntry.initialStateEon < ledger.currentEon().sub(1));
challengeEntry.initialStateEon = ledger.currentEon().sub(1);
challengeEntry.initialStateBalance = owed;
challengeEntry.deltaHighestSpendings = spentGained[0];
challengeEntry.deltaHighestGains = spentGained[1];
challengeEntry.trailIdentifier = trail;
challengeEntry.challengeType = BimodalLib.ChallengeType.STATE_UPDATE;
challengeEntry.block = block.number;
markChallengeLive(ledger, token, msg.sender, msg.sender);
}
function checkStateUpdateBalance(
BimodalLib.Ledger storage ledger,
ERC20 token,
address issuer,
BimodalLib.Challenge storage challenge,
uint256[2] LR,
uint256[2] spentGained,
uint256 passivelyReceived
) private view {
(uint256 deposits, uint256 withdrawals) = ledger
.getCurrentEonDepositsWithdrawals(token, issuer);
uint256 incoming = spentGained[1]
.add(deposits)
.add(passivelyReceived);
uint256 outgoing = spentGained[0]
.add(withdrawals);
require(
challenge.initialStateBalance.add(incoming) <=
LR[1]
.sub(LR[0])
.add(outgoing),
"B"
);
}
function challengeStateUpdateWithProofOfExclusiveBalanceAllotment(
BimodalLib.Ledger storage ledger,
ERC20 token,
bytes32[2] checksums,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] value,
uint256[2][3] lrDeltasPassiveMark,
bytes32[3] rsTxSetRoot,
uint8 v
) public
{
uint256 previousEon = ledger.currentEon().sub(1);
address operator = ledger.operator;
if (lrDeltasPassiveMark[1][0] != 0 || lrDeltasPassiveMark[1][1] != 0) {
verifyProofOfActiveStateUpdateAgreement(
token,
msg.sender,
trail,
previousEon,
rsTxSetRoot[2],
lrDeltasPassiveMark[1],
operator,
rsTxSetRoot[0],
rsTxSetRoot[1],
v
);
}
initStateUpdateChallenge(
ledger,
token,
lrDeltasPassiveMark[0][1].sub(lrDeltasPassiveMark[0][0]),
lrDeltasPassiveMark[1],
trail
);
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
msg.sender,
checksums,
trail,
[
previousEon,
lrDeltasPassiveMark[2][0],
lrDeltasPassiveMark[2][1]
],
allotmentChain,
membershipChain,
value,
lrDeltasPassiveMark[0]
)
);
}
function challengeStateUpdateWithProofOfActiveStateUpdateAgreement(
BimodalLib.Ledger storage ledger,
ERC20 token,
bytes32 txSetRoot,
uint64 trail,
uint256[2] deltas,
bytes32 r,
bytes32 s,
uint8 v
) public
{
verifyProofOfActiveStateUpdateAgreement(
token,
msg.sender,
trail,
ledger.currentEon().sub(1),
txSetRoot,
deltas,
ledger.operator,
r,
s,
v
);
initStateUpdateChallenge(ledger, token, 0, deltas, trail);
}
function answerStateUpdateChallenge(
BimodalLib.Ledger storage ledger,
ERC20 token,
address issuer,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
bytes32[6] rSrStxSetRootChecksum,
uint8[2] v
) public {
BimodalLib.Challenge storage challenge = ledger
.challengeBook[token][issuer][issuer];
require(
challenge.challengeType == BimodalLib.ChallengeType.STATE_UPDATE
);
if (lrDeltasPassiveMark[1][0] != 0 || lrDeltasPassiveMark[1][1] != 0) {
rSrStxSetRootChecksum[0] = verifyProofOfActiveStateUpdateAgreement(
token,
issuer,
challenge.trailIdentifier,
challenge.initialStateEon,
rSrStxSetRootChecksum[4],
lrDeltasPassiveMark[1],
issuer,
rSrStxSetRootChecksum[0],
rSrStxSetRootChecksum[1],
v[0]
);
address operator = ledger.operator;
rSrStxSetRootChecksum[1] = verifyProofOfActiveStateUpdateAgreement(
token,
issuer,
challenge.trailIdentifier,
challenge.initialStateEon,
rSrStxSetRootChecksum[4],
lrDeltasPassiveMark[1],
operator,
rSrStxSetRootChecksum[2],
rSrStxSetRootChecksum[3],
v[1]
);
require(rSrStxSetRootChecksum[0] == rSrStxSetRootChecksum[1], "u");
} else {
rSrStxSetRootChecksum[0] = bytes32(0);
}
require(
lrDeltasPassiveMark[1][0] >= challenge.deltaHighestSpendings &&
lrDeltasPassiveMark[1][1] >= challenge.deltaHighestGains,
"x"
);
checkStateUpdateBalance(
ledger,
token,
issuer,
challenge,
lrDeltasPassiveMark[0],
lrDeltasPassiveMark[1],
lrDeltasPassiveMark[2][0]
);
emit StateUpdate(
token,
issuer,
challenge.initialStateEon.add(1),
challenge.trailIdentifier,
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark,
rSrStxSetRootChecksum[0],
rSrStxSetRootChecksum[5],
rSrStxSetRootChecksum[2],
rSrStxSetRootChecksum[3],
v[1]
);
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
issuer,
[rSrStxSetRootChecksum[0], rSrStxSetRootChecksum[5]],
challenge.trailIdentifier,
[
challenge.initialStateEon.add(1),
lrDeltasPassiveMark[2][0],
lrDeltasPassiveMark[2][1]
],
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark[0]
),
"c"
);
markChallengeAnswered(ledger, challenge);
}
function initTransferDeliveryChallenge(
BimodalLib.Ledger storage ledger,
ERC20 token,
address sender,
address recipient,
uint256 amount,
uint256 txNonce,
uint64 trail
) private {
BimodalLib.Challenge storage challenge = ledger
.challengeBook[token][recipient][sender];
require(challenge.challengeType == BimodalLib.ChallengeType.NONE);
require(challenge.initialStateEon < ledger.currentEon().sub(1));
challenge.challengeType = BimodalLib.ChallengeType.TRANSFER_DELIVERY;
challenge.initialStateEon = ledger.currentEon().sub(1);
challenge.deliveredTxNonce = txNonce;
challenge.block = block.number;
challenge.trailIdentifier = trail;
challenge.finalStateBalance = amount;
markChallengeLive(ledger, token, recipient, sender);
}
function challengeTransferDeliveryWithProofOfActiveStateUpdateAgreement(
BimodalLib.Ledger storage ledger,
ERC20 token,
address[2] SR,
uint256[2] nonceAmount,
uint64[3] trails,
bytes32[] chain,
uint256[2] deltas,
bytes32[3] rsTxSetRoot,
uint8 v
) public
{
require(msg.sender == SR[0] || msg.sender == SR[1], "d");
verifyProofOfActiveStateUpdateAgreement(
token,
SR[0],
trails[0],
ledger.currentEon().sub(1),
rsTxSetRoot[2],
deltas,
ledger.operator,
rsTxSetRoot[0],
rsTxSetRoot[1],
v
);
rsTxSetRoot[0] = MerkleVerifier.transferChecksum(
SR[1],
nonceAmount[1],
trails[2],
nonceAmount[0]
);
require(
MerkleVerifier.verifyProofOfMembership(
trails[1],
chain,
rsTxSetRoot[0],
rsTxSetRoot[2]
),
"e"
);
initTransferDeliveryChallenge(
ledger,
token,
SR[0],
SR[1],
nonceAmount[1],
nonceAmount[0],
trails[2]
);
}
function answerTransferDeliveryChallengeWithProofOfActiveStateUpdateAgreement(
BimodalLib.Ledger storage ledger,
ERC20 token,
address[2] SR,
uint64 transferMembershipTrail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
bytes32[2] txSetRootChecksum,
bytes32[] txChain
) public {
BimodalLib.Challenge storage challenge = ledger
.challengeBook[token][SR[1]][SR[0]];
require(
challenge.challengeType ==
BimodalLib.ChallengeType.TRANSFER_DELIVERY
);
require(
MerkleVerifier.verifyProofOfMembership(
transferMembershipTrail,
txChain,
MerkleVerifier.transferChecksum(
SR[0],
challenge.finalStateBalance,
challenge.trailIdentifier,
challenge.deliveredTxNonce
),
txSetRootChecksum[0]
)
);
txSetRootChecksum[0] = MerkleVerifier.activeStateUpdateChecksum(
token,
SR[1],
challenge.trailIdentifier,
challenge.initialStateEon,
txSetRootChecksum[0],
lrDeltasPassiveMark[1]
);
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
SR[1],
txSetRootChecksum,
challenge.trailIdentifier,
[
challenge.initialStateEon.add(1),
lrDeltasPassiveMark[2][0],
lrDeltasPassiveMark[2][1]
],
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark[0]
)
);
markChallengeAnswered(ledger, challenge);
}
function challengeTransferDeliveryWithProofOfPassiveStateUpdate(
BimodalLib.Ledger storage ledger,
ERC20 token,
address[2] SR,
bytes32[2] txSetRootChecksum,
uint64[3] senderTransferRecipientTrails,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][4] lrDeltasPassiveMarkDummyAmount,
bytes32[] transferMembershipChain
) public
{
require(msg.sender == SR[0] || msg.sender == SR[1], "d");
lrDeltasPassiveMarkDummyAmount[3][0] = ledger.currentEon().sub(1);
require(
MerkleVerifier.verifyProofOfMembership(
senderTransferRecipientTrails[1],
transferMembershipChain,
MerkleVerifier.transferChecksum(
SR[1],
lrDeltasPassiveMarkDummyAmount[3][1],
senderTransferRecipientTrails[2],
2**256 - 1
),
txSetRootChecksum[0]
),
"e"
);
txSetRootChecksum[0] = MerkleVerifier.activeStateUpdateChecksum(
token,
SR[0],
senderTransferRecipientTrails[0],
lrDeltasPassiveMarkDummyAmount[3][0],
txSetRootChecksum[0],
lrDeltasPassiveMarkDummyAmount[1]
);
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
SR[0],
txSetRootChecksum,
senderTransferRecipientTrails[0],
[
lrDeltasPassiveMarkDummyAmount[3][0].add(1),
lrDeltasPassiveMarkDummyAmount[2][0],
lrDeltasPassiveMarkDummyAmount[2][1]
],
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMarkDummyAmount[0]
)
);
initTransferDeliveryChallenge(
ledger,
token,
SR[0],
SR[1],
lrDeltasPassiveMarkDummyAmount[3][1],
uint256(
keccak256(
abi.encodePacked(
lrDeltasPassiveMarkDummyAmount[2][1],
uint256(2**256 - 1)
)
)
),
senderTransferRecipientTrails[2]
);
}
function answerTransferDeliveryChallengeWithProofOfPassiveStateUpdate(
BimodalLib.Ledger storage ledger,
ERC20 token,
address[2] SR,
uint64 transferMembershipTrail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrPassiveMarkPositionNonce,
bytes32[2] checksums,
bytes32[] txChainValues
) public {
BimodalLib.Challenge storage challenge = ledger
.challengeBook[token][SR[1]][SR[0]];
require(
challenge.challengeType ==
BimodalLib.ChallengeType.TRANSFER_DELIVERY
);
require(
challenge.deliveredTxNonce ==
uint256(
keccak256(
abi.encodePacked(
lrPassiveMarkPositionNonce[2][0],
lrPassiveMarkPositionNonce[2][1]
)
)
)
);
require(
MerkleVerifier.verifyProofOfPassiveDelivery(
transferMembershipTrail,
MerkleVerifier.transferChecksum(
SR[0],
challenge.finalStateBalance,
challenge.trailIdentifier,
challenge.deliveredTxNonce
),
checksums[1],
txChainValues,
[
lrPassiveMarkPositionNonce[2][0],
lrPassiveMarkPositionNonce[2][0].add(
challenge.finalStateBalance
)
]
) <= lrPassiveMarkPositionNonce[1][0]
);
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
SR[1],
checksums,
challenge.trailIdentifier,
[
challenge.initialStateEon.add(1),
lrPassiveMarkPositionNonce[1][0],
lrPassiveMarkPositionNonce[1][1]
],
allotmentChain,
membershipChain,
values,
lrPassiveMarkPositionNonce[0]
)
);
markChallengeAnswered(ledger, challenge);
}
function initSwapEnactmentChallenge(
BimodalLib.Ledger storage ledger,
ERC20[2] tokens,
uint256[4] updatedSpentGainedPassive,
uint256[4] sellBuyBalanceNonce,
uint64 recipientTrail
) private {
ERC20 conduit = ERC20(
address(keccak256(abi.encodePacked(tokens[0], tokens[1])))
);
BimodalLib.Challenge storage challenge = ledger
.challengeBook[conduit][msg.sender][msg.sender];
require(challenge.challengeType == BimodalLib.ChallengeType.NONE);
require(challenge.initialStateEon < ledger.currentEon().sub(1));
challenge.initialStateEon = ledger.currentEon().sub(1);
challenge.deliveredTxNonce = sellBuyBalanceNonce[3];
challenge.challengeType = BimodalLib.ChallengeType.SWAP_ENACTMENT;
challenge.block = block.number;
challenge.trailIdentifier = recipientTrail;
challenge.deltaHighestSpendings = sellBuyBalanceNonce[0];
challenge.deltaHighestGains = sellBuyBalanceNonce[1];
(uint256 deposits, uint256 withdrawals) = ledger
.getCurrentEonDepositsWithdrawals(tokens[0], msg.sender);
challenge.initialStateBalance = sellBuyBalanceNonce[2]
.add(updatedSpentGainedPassive[2])
.add(updatedSpentGainedPassive[3])
.add(deposits)
.sub(updatedSpentGainedPassive[1])
.sub(withdrawals);
challenge.finalStateBalance = updatedSpentGainedPassive[0];
require(
challenge.finalStateBalance >= challenge.initialStateBalance,
"d"
);
markChallengeLive(ledger, conduit, msg.sender, msg.sender);
}
function challengeSwapEnactmentWithProofOfActiveStateUpdateAgreement(
BimodalLib.Ledger storage ledger,
ERC20[2] tokens,
uint64[3] senderTransferRecipientTrails,
bytes32[] allotmentChain,
bytes32[] membershipChain,
bytes32[] txChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
uint256[4] sellBuyBalanceNonce,
bytes32[3] txSetRootChecksumDummy
) public
{
txSetRootChecksumDummy[2] = MerkleVerifier.swapOrderChecksum(
tokens,
senderTransferRecipientTrails[2],
sellBuyBalanceNonce[0],
sellBuyBalanceNonce[1],
sellBuyBalanceNonce[2],
sellBuyBalanceNonce[3]
);
require(
MerkleVerifier.verifyProofOfMembership(
senderTransferRecipientTrails[1],
txChain,
txSetRootChecksumDummy[2],
txSetRootChecksumDummy[0]
),
"e"
);
uint256 previousEon = ledger.currentEon().sub(1);
txSetRootChecksumDummy[2] = MerkleVerifier.activeStateUpdateChecksum(
tokens[0],
msg.sender,
senderTransferRecipientTrails[0],
previousEon,
txSetRootChecksumDummy[0],
lrDeltasPassiveMark[1]
);
uint256 updatedBalance = lrDeltasPassiveMark[0][1].sub(
lrDeltasPassiveMark[0][0]
);
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
tokens[0],
msg.sender,
[txSetRootChecksumDummy[2], txSetRootChecksumDummy[1]],
senderTransferRecipientTrails[0],
[
previousEon.add(1),
lrDeltasPassiveMark[2][0],
lrDeltasPassiveMark[2][1]
],
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark[0]
)
);
initSwapEnactmentChallenge(
ledger,
tokens,
[
updatedBalance,
lrDeltasPassiveMark[1][0],
lrDeltasPassiveMark[1][1],
lrDeltasPassiveMark[2][0]
],
sellBuyBalanceNonce,
senderTransferRecipientTrails[2]
);
}
function calculateSwapConsistencyBalance(
BimodalLib.Ledger storage ledger,
ERC20 token,
uint256[2] deltas,
uint256 passiveAmount,
uint256 balance
) private view returns (uint256) {
(uint256 deposits, uint256 withdrawals) = ledger
.getCurrentEonDepositsWithdrawals(token, msg.sender);
return
balance
.add(deltas[1])
.add(passiveAmount)
.add(deposits)
.sub(withdrawals)
.sub(deltas[0]);
}
function verifySwapConsistency(
BimodalLib.Ledger storage ledger,
ERC20[2] tokens,
BimodalLib.Challenge challenge,
uint256[2] LR,
uint256[2] deltas,
uint256 passiveAmount,
uint256 balance
) private view returns (bool) {
balance = calculateSwapConsistencyBalance(
ledger,
tokens[1],
deltas,
passiveAmount,
balance
);
require(LR[1].sub(LR[0]) >= balance);
uint256 taken = challenge
.deltaHighestSpendings
.sub(
challenge.finalStateBalance.sub(challenge.initialStateBalance)
);
uint256 given = LR[1]
.sub(LR[0])
.sub(balance);
return
taken.mul(challenge.deltaHighestGains).div(100) >=
challenge.deltaHighestSpendings.mul(given).div(100);
}
function answerSwapChallengeWithProofOfExclusiveBalanceAllotment(
BimodalLib.Ledger storage ledger,
ERC20[2] tokens,
address issuer,
uint64 transferMembershipTrail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
bytes32[] txChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
uint256 balance,
bytes32[3] txSetRootChecksumDummy
) public {
ERC20 conduit = ERC20(
address(keccak256(abi.encodePacked(tokens[0], tokens[1])))
);
BimodalLib.Challenge storage challenge = ledger
.challengeBook[conduit][issuer][issuer];
require(
challenge.challengeType == BimodalLib.ChallengeType.SWAP_ENACTMENT
);
txSetRootChecksumDummy[2] = MerkleVerifier.swapOrderChecksum(
tokens,
challenge.trailIdentifier,
challenge.deltaHighestSpendings,
challenge.deltaHighestGains,
balance,
challenge.deliveredTxNonce
);
require(
MerkleVerifier.verifyProofOfMembership(
transferMembershipTrail,
txChain,
txSetRootChecksumDummy[2],
txSetRootChecksumDummy[0]
),
"M"
);
txSetRootChecksumDummy[2] = MerkleVerifier.activeStateUpdateChecksum(
tokens[1],
issuer,
challenge.trailIdentifier,
challenge.initialStateEon,
txSetRootChecksumDummy[0],
lrDeltasPassiveMark[1]
);
if (balance != 2**256 - 1) {
require(
verifySwapConsistency(
ledger,
tokens,
challenge,
lrDeltasPassiveMark[0],
lrDeltasPassiveMark[1],
lrDeltasPassiveMark[2][0],
balance
),
"v"
);
}
require(
verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
tokens[1],
issuer,
[txSetRootChecksumDummy[2], txSetRootChecksumDummy[1]],
challenge.trailIdentifier,
[
challenge.initialStateEon.add(1),
lrDeltasPassiveMark[2][0],
lrDeltasPassiveMark[2][1]
],
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark[0]
),
"s"
);
markChallengeAnswered(ledger, challenge);
}
function slashWithdrawalWithProofOfMinimumAvailableBalance(
BimodalLib.Ledger storage ledger,
ERC20 token,
address withdrawer,
uint256[2] markerEonAvailable,
bytes32[2] rs,
uint8 v
) public returns (uint256[2] amounts) {
uint256 latestEon = ledger.currentEon();
require(latestEon < markerEonAvailable[0].add(3), "m");
bytes32 checksum = keccak256(
abi.encodePacked(
keccak256(abi.encodePacked(address(this))),
keccak256(abi.encodePacked(token)),
keccak256(abi.encodePacked(withdrawer)),
markerEonAvailable[0],
markerEonAvailable[1]
)
);
require(
withdrawer ==
BimodalLib.signedMessageECRECOVER(checksum, rs[0], rs[1], v)
);
BimodalLib.Wallet storage entry = ledger.walletBook[token][withdrawer];
BimodalLib.Withdrawal[] storage withdrawals = entry.withdrawals;
for (uint32 i = 1; i <= withdrawals.length; i++) {
BimodalLib.Withdrawal storage withdrawal = withdrawals[withdrawals
.length
.sub(i)];
if (withdrawal.eon.add(1) < latestEon) {
break;
} else if (withdrawal.eon == latestEon.sub(1)) {
amounts[0] = amounts[0].add(withdrawal.amount);
} else if (withdrawal.eon == latestEon) {
amounts[1] = amounts[1].add(withdrawal.amount);
}
}
require(amounts[0].add(amounts[1]) > markerEonAvailable[1]);
withdrawals.length = withdrawals.length.sub(i.sub(1));
if (amounts[1] > 0) {
ledger.deductFromRunningPendingWithdrawals(
token,
latestEon,
latestEon,
amounts[1]
);
ledger.appendOperationToEonAccumulator(
latestEon,
token,
withdrawer,
BimodalLib.Operation.CANCELLATION,
amounts[1]
);
}
if (amounts[0] > 0) {
ledger.deductFromRunningPendingWithdrawals(
token,
latestEon.sub(1),
latestEon,
amounts[0]
);
ledger.appendOperationToEonAccumulator(
latestEon.sub(1),
token,
withdrawer,
BimodalLib.Operation.CANCELLATION,
amounts[0]
);
}
}
}
文件 4 的 19:ChallengeProxy.sol
pragma solidity ^0.4.24;
import "./BimodalProxy.sol";
import "./ERC20.sol";
import "./BimodalLib.sol";
import "./MerkleVerifier.sol";
import "./ChallengeLib.sol";
import "./SafeMathLib256.sol";
contract ChallengeProxy is BimodalProxy {
using SafeMathLib256 for uint256;
modifier onlyWithFairReimbursement() {
uint256 gas = gasleft();
_;
gas = gas.sub(gasleft());
require(
msg.value >= gas.mul(ledger.MIN_CHALLENGE_GAS_COST) &&
msg.value >= gas.mul(tx.gasprice),
'r');
ledger.operator.transfer(msg.value);
}
modifier onlyWithSkewedReimbursement(uint256 extra) {
uint256 gas = gasleft();
_;
gas = gas.sub(gasleft());
require(
msg.value >= gas.add(extra).mul(ledger.MIN_CHALLENGE_GAS_COST) &&
msg.value >= gas.add(extra).mul(tx.gasprice),
'r');
ledger.operator.transfer(msg.value);
}
function verifyProofOfExclusiveAccountBalanceAllotment(
ERC20 token,
address holder,
bytes32[2] activeStateChecksum_passiveTransfersRoot,
uint64 trail,
uint256[3] eonPassiveMark,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2] LR
)
public
view
returns (bool)
{
return ChallengeLib.verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
holder,
activeStateChecksum_passiveTransfersRoot,
trail,
eonPassiveMark,
allotmentChain,
membershipChain,
values,
LR
);
}
function verifyProofOfActiveStateUpdateAgreement(
ERC20 token,
address holder,
uint64 trail,
uint256 eon,
bytes32 txSetRoot,
uint256[2] deltas,
address attester, bytes32 r, bytes32 s, uint8 v
)
public
view
returns (bytes32 checksum)
{
return ChallengeLib.verifyProofOfActiveStateUpdateAgreement(
token,
holder,
trail,
eon,
txSetRoot,
deltas,
attester,
r,
s,
v
);
}
function verifyWithdrawalAuthorization(
ERC20 token,
address holder,
uint256 expiry,
uint256 amount,
address attester,
bytes32 r, bytes32 s, uint8 v
)
public
view
returns (bool)
{
return ChallengeLib.verifyWithdrawalAuthorization(
token,
holder,
expiry,
amount,
attester,
r,
s,
v
);
}
function verifyProofOfExclusiveBalanceAllotment(
uint64 allotmentTrail,
uint64 membershipTrail,
bytes32 node,
bytes32 root,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] value,
uint256[2] LR
)
public
pure
returns (uint256)
{
return MerkleVerifier.verifyProofOfExclusiveBalanceAllotment(
allotmentTrail,
membershipTrail,
node,
root,
allotmentChain,
membershipChain,
value,
LR
);
}
function verifyProofOfMembership(
uint256 trail,
bytes32[] chain,
bytes32 node,
bytes32 merkleRoot
)
public
pure
returns (bool)
{
return MerkleVerifier.verifyProofOfMembership(
trail,
chain,
node,
merkleRoot
);
}
function verifyProofOfPassiveDelivery(
uint64 allotmentTrail,
bytes32 node,
bytes32 root,
bytes32[] chainValues,
uint256[2] LR
)
public
pure
returns (uint256)
{
return MerkleVerifier.verifyProofOfPassiveDelivery(
allotmentTrail,
node,
root,
chainValues,
LR
);
}
function challengeStateUpdateWithProofOfExclusiveBalanceAllotment(
ERC20 token,
bytes32[2] checksums,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] value,
uint256[2][3] lrDeltasPassiveMark,
bytes32[3] rsTxSetRoot,
uint8 v
)
public
payable
onlyWithFairReimbursement()
{
ChallengeLib.challengeStateUpdateWithProofOfExclusiveBalanceAllotment(
ledger,
token,
checksums,
trail,
allotmentChain,
membershipChain,
value,
lrDeltasPassiveMark,
rsTxSetRoot,
v
);
}
function challengeStateUpdateWithProofOfActiveStateUpdateAgreement(
ERC20 token,
bytes32 txSetRoot,
uint64 trail,
uint256[2] deltas,
bytes32 r, bytes32 s, uint8 v
)
public
payable
onlyWithSkewedReimbursement(25)
{
ChallengeLib.challengeStateUpdateWithProofOfActiveStateUpdateAgreement(
ledger,
token,
txSetRoot,
trail,
deltas,
r,
s,
v
);
}
function answerStateUpdateChallenge(
ERC20 token,
address issuer,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
bytes32[6] rSrStxSetRootChecksum,
uint8[2] v
)
public
{
ChallengeLib.answerStateUpdateChallenge(
ledger,
token,
issuer,
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark,
rSrStxSetRootChecksum,
v
);
}
function challengeTransferDeliveryWithProofOfActiveStateUpdateAgreement(
ERC20 token,
address[2] SR,
uint256[2] nonceAmount,
uint64[3] trails,
bytes32[] chain,
uint256[2] deltas,
bytes32[3] rsTxSetRoot,
uint8 v
)
public
payable
onlyWithFairReimbursement()
{
ChallengeLib.challengeTransferDeliveryWithProofOfActiveStateUpdateAgreement(
ledger,
token,
SR,
nonceAmount,
trails,
chain,
deltas,
rsTxSetRoot,
v
);
}
function answerTransferDeliveryChallengeWithProofOfActiveStateUpdateAgreement(
ERC20 token,
address[2] SR,
uint64 transferMembershipTrail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
bytes32[2] txSetRootChecksum,
bytes32[] txChain
)
public
{
ChallengeLib.answerTransferDeliveryChallengeWithProofOfActiveStateUpdateAgreement(
ledger,
token,
SR,
transferMembershipTrail,
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMark,
txSetRootChecksum,
txChain
);
}
function challengeTransferDeliveryWithProofOfPassiveStateUpdate(
ERC20 token,
address[2] SR,
bytes32[2] txSetRootChecksum,
uint64[3] senderTransferRecipientTrails,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][4] lrDeltasPassiveMarkDummyAmount,
bytes32[] transferMembershipChain
)
public
payable
onlyWithFairReimbursement()
{
ChallengeLib.challengeTransferDeliveryWithProofOfPassiveStateUpdate(
ledger,
token,
SR,
txSetRootChecksum,
senderTransferRecipientTrails,
allotmentChain,
membershipChain,
values,
lrDeltasPassiveMarkDummyAmount,
transferMembershipChain
);
}
function answerTransferDeliveryChallengeWithProofOfPassiveStateUpdate(
ERC20 token,
address[2] SR,
uint64 transferMembershipTrail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][3] lrPassiveMarkPositionNonce,
bytes32[2] checksums,
bytes32[] txChainValues
)
public
{
ChallengeLib.answerTransferDeliveryChallengeWithProofOfPassiveStateUpdate(
ledger,
token,
SR,
transferMembershipTrail,
allotmentChain,
membershipChain,
values,
lrPassiveMarkPositionNonce,
checksums,
txChainValues
);
}
function challengeSwapEnactmentWithProofOfActiveStateUpdateAgreement(
ERC20[2] tokens,
uint64[3] senderTransferRecipientTrails,
bytes32[] allotmentChain,
bytes32[] membershipChain,
bytes32[] txChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
uint256[4] sellBuyBalanceNonce,
bytes32[3] txSetRootChecksumDummy
)
public
payable
onlyWithFairReimbursement()
{
ChallengeLib.challengeSwapEnactmentWithProofOfActiveStateUpdateAgreement(
ledger,
tokens,
senderTransferRecipientTrails,
allotmentChain,
membershipChain,
txChain,
values,
lrDeltasPassiveMark,
sellBuyBalanceNonce,
txSetRootChecksumDummy
);
}
function answerSwapChallengeWithProofOfExclusiveBalanceAllotment(
ERC20[2] tokens,
address issuer,
uint64 transferMembershipTrail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
bytes32[] txChain,
uint256[] values,
uint256[2][3] lrDeltasPassiveMark,
uint256 balance,
bytes32[3] txSetRootChecksumDummy
)
public
{
ChallengeLib.answerSwapChallengeWithProofOfExclusiveBalanceAllotment(
ledger,
tokens,
issuer,
transferMembershipTrail,
allotmentChain,
membershipChain,
txChain,
values,
lrDeltasPassiveMark,
balance,
txSetRootChecksumDummy
);
}
function slashWithdrawalWithProofOfMinimumAvailableBalance(
ERC20 token,
address withdrawer,
uint256[2] markerEonAvailable,
bytes32[2] rs,
uint8 v
)
public
returns (uint256[2])
{
return ChallengeLib.slashWithdrawalWithProofOfMinimumAvailableBalance(
ledger,
token,
withdrawer,
markerEonAvailable,
rs,
v
);
}
}
文件 5 的 19:DepositLib.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./BimodalLib.sol";
import "./SafeMathLib256.sol";
library DepositLib {
using SafeMathLib256 for uint256;
using BimodalLib for BimodalLib.Ledger;
event Deposit(address indexed token, address indexed recipient, uint256 amount);
function deposit(
BimodalLib.Ledger storage ledger,
ERC20 token,
address beneficiary,
uint256 amount
)
public
{
uint256 eon = ledger.currentEon();
uint256 value = msg.value;
if (token != address(this)) {
require(ledger.tokenToTrail[token] != 0,
't');
require(msg.value == 0,
'm');
require(token.transferFrom(beneficiary, this, amount),
'f');
value = amount;
}
BimodalLib.Wallet storage entry = ledger.walletBook[token][beneficiary];
BimodalLib.AmountAggregate storage depositAggregate = entry.depositsKept[eon.mod(ledger.DEPOSITS_KEPT)];
BimodalLib.addToAggregate(depositAggregate, eon, value);
BimodalLib.AmountAggregate storage eonDeposits = ledger.deposits[token][eon.mod(ledger.EONS_KEPT)];
BimodalLib.addToAggregate(eonDeposits, eon, value);
ledger.appendOperationToEonAccumulator(eon, token, beneficiary, BimodalLib.Operation.DEPOSIT, value);
emit Deposit(token, beneficiary, value);
}
}
文件 6 的 19:DepositProxy.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./BimodalLib.sol";
import "./BimodalProxy.sol";
import "./DepositLib.sol";
import "./SafeMathLib256.sol";
contract DepositProxy is BimodalProxy {
using SafeMathLib256 for uint256;
function()
public
payable
{}
function deposit(
ERC20 token,
address beneficiary,
uint256 amount
)
public
payable
onlyWhenContractUnpunished()
{
DepositLib.deposit(
ledger,
token,
beneficiary,
amount);
}
}
文件 7 的 19:ERC20.sol
pragma solidity ^0.4.24;
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender)
public view returns (uint256);
function transferFrom(address from, address to, uint256 value)
public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
文件 8 的 19:ERC20TokenImplementation.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./SafeMathLib256.sol";
contract BasicToken is ERC20Basic {
using SafeMathLib256 for uint256;
mapping(address => uint256) internal balances;
uint256 internal totalSupply_;
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
}
contract StandardToken is ERC20, BasicToken {
using SafeMathLib256 for uint256;
mapping (address => mapping (address => uint256)) internal allowed;
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}
function increaseApproval(
address _spender,
uint256 _addedValue
)
public
returns (bool)
{
allowed[msg.sender][_spender] = (
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval(
address _spender,
uint256 _subtractedValue
)
public
returns (bool)
{
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
contract DetailedERC20 is ERC20 {
using SafeMathLib256 for uint256;
string public name;
string public symbol;
uint8 public decimals;
constructor(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
interface ApprovalSpender {
function receiveApproval(address from, uint256 value, address token, bytes data) external;
}
contract ERC20TokenImplementation is StandardToken, DetailedERC20 {
using SafeMathLib256 for uint256;
constructor()
public
DetailedERC20("Liquidity.Network Token", "LQD", 18)
{
totalSupply_ = 100000000 * (10 ** uint256(decimals));
balances[msg.sender] = totalSupply_;
emit Transfer(0x0, msg.sender, totalSupply_);
}
function approveAndCall(ApprovalSpender recipientContract, uint256 value, bytes data) public returns (bool) {
if (approve(recipientContract, value)) {
recipientContract.receiveApproval(msg.sender, value, address(this), data);
return true;
}
}
}
文件 9 的 19:MerkleVerifier.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./SafeMathLib32.sol";
import "./SafeMathLib64.sol";
import "./SafeMathLib256.sol";
library MerkleVerifier {
using SafeMathLib32 for uint32;
using SafeMathLib64 for uint64;
using SafeMathLib256 for uint256;
function calculateMerkleRoot(
uint256 trail,
bytes32[] chain,
bytes32 node
) public pure returns (bytes32) {
for (uint32 i = 0; i < chain.length; i++) {
bool linkLeft = false;
if (trail > 0) {
linkLeft = trail.mod(2) == 1;
trail = trail.div(2);
}
node = keccak256(
abi.encodePacked(
i,
linkLeft ? chain[i] : node,
linkLeft ? node : chain[i]
)
);
}
return node;
}
function verifyProofOfMembership(
uint256 trail,
bytes32[] chain,
bytes32 node,
bytes32 merkleRoot
) public pure returns (bool) {
return calculateMerkleRoot(trail, chain, node) == merkleRoot;
}
function verifyProofOfExclusiveBalanceAllotment(
uint64 allotmentTrail,
uint64 membershipTrail,
bytes32 node,
bytes32 root,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] value,
uint256[2] LR
) public pure returns (uint256) {
require(value.length == allotmentChain.length, "p");
require(LR[1] >= LR[0], "s");
for (uint32 i = 0; i < value.length; i++) {
bool linkLeft = false;
if (allotmentTrail > 0) {
linkLeft = allotmentTrail.mod(2) == 1;
allotmentTrail = allotmentTrail.div(2);
}
node = keccak256(
abi.encodePacked(
i,
linkLeft ? value[i] : LR[0],
keccak256(
abi.encodePacked(
linkLeft ? allotmentChain[i] : node,
linkLeft ? LR[0] : LR[1],
linkLeft ? node : allotmentChain[i]
)
),
linkLeft ? LR[1] : value[i]
)
);
require(linkLeft ? value[i] <= LR[0] : LR[1] <= value[i], "x");
LR[0] = linkLeft ? value[i] : LR[0];
LR[1] = linkLeft ? LR[1] : value[i];
require(LR[1] >= LR[0], "t");
}
require(LR[0] == 0, "l");
node = keccak256(abi.encodePacked(LR[0], node, LR[1]));
require(
verifyProofOfMembership(
membershipTrail,
membershipChain,
node,
root
),
"m"
);
return LR[1];
}
function verifyProofOfPassiveDelivery(
uint64 allotmentTrail,
bytes32 node,
bytes32 root,
bytes32[] chainValues,
uint256[2] LR
) public pure returns (uint256) {
require(chainValues.length.mod(2) == 0, "p");
require(LR[1] >= LR[0], "s");
uint32 v = uint32(chainValues.length.div(2));
for (uint32 i = 0; i < v; i++) {
bool linkLeft = false;
if (allotmentTrail > 0) {
linkLeft = allotmentTrail.mod(2) == 1;
allotmentTrail = allotmentTrail.div(2);
}
node = keccak256(
abi.encodePacked(
i,
linkLeft ? uint256(chainValues[i.add(v)]) : LR[0],
keccak256(
abi.encodePacked(
linkLeft ? chainValues[i] : node,
linkLeft ? LR[0] : LR[1],
linkLeft ? node : chainValues[i]
)
),
linkLeft ? LR[1] : uint256(chainValues[i.add(v)])
)
);
require(
linkLeft
? uint256(chainValues[i.add(v)]) <= LR[0]
: LR[1] <= uint256(chainValues[i.add(v)]),
"x"
);
LR[0] = linkLeft ? uint256(chainValues[i.add(v)]) : LR[0];
LR[1] = linkLeft ? LR[1] : uint256(chainValues[i.add(v)]);
require(LR[1] >= LR[0], "t");
}
require(LR[0] == 0, "l");
require(node == root, "n");
return LR[1];
}
function transferChecksum(
address counterparty,
uint256 amount,
uint64 recipientTrail,
uint256 nonce
) public pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
keccak256(abi.encodePacked(counterparty)),
amount,
recipientTrail,
nonce
)
);
}
function swapOrderChecksum(
ERC20[2] tokens,
uint64 recipientTrail,
uint256 sellAmount,
uint256 buyAmount,
uint256 startBalance,
uint256 nonce
) public pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
keccak256(abi.encodePacked(tokens[0])),
keccak256(abi.encodePacked(tokens[1])),
recipientTrail,
sellAmount,
buyAmount,
startBalance,
nonce
)
);
}
function activeStateUpdateChecksum(
ERC20 token,
address holder,
uint64 trail,
uint256 eon,
bytes32 txSetRoot,
uint256[2] deltas
) public view returns (bytes32) {
return
keccak256(
abi.encodePacked(
keccak256(abi.encodePacked(address(this))),
keccak256(abi.encodePacked(token)),
keccak256(abi.encodePacked(holder)),
trail,
eon,
txSetRoot,
deltas[0],
deltas[1]
)
);
}
}
文件 10 的 19:MerkleVerifierProxy.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./MerkleVerifier.sol";
contract MerkleVerifierProxy {
function calculateMerkleRoot(
uint256 trail,
bytes32[] chain,
bytes32 node
)
public
pure
returns (bytes32)
{
return MerkleVerifier.calculateMerkleRoot(trail, chain, node);
}
function verifyProofOfExclusiveBalanceAllotment(
uint64 allotmentTrail,
uint64 membershipTrail,
bytes32 node,
bytes32 root,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] value,
uint256[2] LR
)
public
pure
returns (uint256)
{
return MerkleVerifier.verifyProofOfExclusiveBalanceAllotment(
allotmentTrail,
membershipTrail,
node,
root,
allotmentChain,
membershipChain,
value,
LR
);
}
function verifyProofOfPassiveDelivery(
uint64 allotmentTrail,
bytes32 node,
bytes32 root,
bytes32[] chainValues,
uint256[2] LR
)
public
pure
returns (uint256)
{
MerkleVerifier.verifyProofOfPassiveDelivery(
allotmentTrail,
node,
root,
chainValues,
LR
);
}
function transferChecksum(
address counterparty,
uint256 amount,
uint64 recipientTrail,
uint256 nonce
)
public
pure
returns (bytes32)
{
return MerkleVerifier.transferChecksum(
counterparty,
amount,
recipientTrail,
nonce
);
}
function swapOrderChecksum(
ERC20[2] tokens,
uint64 recipientTrail,
uint256 sellAmount,
uint256 buyAmount,
uint256 startBalance,
uint256 nonce
)
public
pure
returns (bytes32)
{
return MerkleVerifier.swapOrderChecksum(
tokens,
recipientTrail,
sellAmount,
buyAmount,
startBalance,
nonce
);
}
function activeStateUpdateChecksum(
ERC20 token,
address holder,
uint64 trail,
uint256 eon,
bytes32 txSetRoot,
uint256[2] deltas
)
public
view
returns (bytes32)
{
return MerkleVerifier.activeStateUpdateChecksum(
token,
holder,
trail,
eon,
txSetRoot,
deltas
);
}
}
文件 11 的 19:Migrations.sol
pragma solidity ^0.4.24;
contract Migrations {
address public owner;
uint256 public lastCompletedMigration;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor()
public
{
owner = msg.sender;
}
function setCompleted(uint256 completed)
public
restricted
{
lastCompletedMigration = completed;
}
function upgrade(address newAddress)
public
restricted
{
Migrations upgraded = Migrations(newAddress);
upgraded.setCompleted(lastCompletedMigration);
}
}
文件 12 的 19:NOCUSTCommitChain.sol
pragma solidity ^0.4.24;
import "./BimodalProxy.sol";
import "./DepositProxy.sol";
import "./WithdrawalProxy.sol";
import "./ChallengeProxy.sol";
import "./RecoveryProxy.sol";
import "./SafeMathLib256.sol";
contract NOCUSTCommitChain is
BimodalProxy,
DepositProxy,
WithdrawalProxy,
ChallengeProxy,
RecoveryProxy
{
using SafeMathLib256 for uint256;
constructor(uint256 blocksPerEon, address operator)
public
BimodalProxy(blocksPerEon, operator)
{
ledger.trailToToken.push(address(this));
ledger.tokenToTrail[address(this)] = 0;
}
function registerERC20(ERC20 token) public onlyOperator() {
require(ledger.tokenToTrail[token] == 0);
ledger.tokenToTrail[token] = uint64(ledger.trailToToken.length);
ledger.trailToToken.push(token);
}
function submitCheckpoint(bytes32 accumulator, bytes32 merkleRoot)
public
onlyOperator()
onlyWhenContractUnpunished()
{
uint256 eon = ledger.currentEon();
require(
ledger.parentChainAccumulator[eon.sub(1).mod(ledger.EONS_KEPT)] ==
accumulator,
"b"
);
require(ledger.getLiveChallenges(eon.sub(1)) == 0, "c");
require(eon > ledger.lastSubmissionEon, "d");
ledger.lastSubmissionEon = eon;
BimodalLib.Checkpoint storage checkpoint = ledger.getOrCreateCheckpoint(
eon,
eon
);
checkpoint.merkleRoot = merkleRoot;
emit CheckpointSubmission(eon, merkleRoot);
}
}
文件 13 的 19:RecoveryLib.sol
pragma solidity ^0.4.24;
import "./ERC20.sol";
import "./BimodalLib.sol";
import "./ChallengeLib.sol";
import "./SafeMathLib256.sol";
library RecoveryLib {
using SafeMathLib256 for uint256;
using BimodalLib for BimodalLib.Ledger;
function reclaimUncommittedDeposits(
BimodalLib.Ledger storage ledger,
BimodalLib.Wallet storage wallet
) private returns (uint256 amount) {
for (uint8 i = 0; i < ledger.DEPOSITS_KEPT; i++) {
BimodalLib.AmountAggregate storage depositAggregate = wallet
.depositsKept[i];
if (depositAggregate.eon.add(1) < ledger.lastSubmissionEon) {
continue;
}
amount = amount.add(depositAggregate.amount);
BimodalLib.clearAggregate(depositAggregate);
}
}
function reclaimFinalizedWithdrawal(
BimodalLib.Ledger storage ledger,
BimodalLib.Wallet storage wallet
) private returns (uint256 amount) {
BimodalLib.Withdrawal[] storage withdrawals = wallet.withdrawals;
for (uint32 i = 0; i < withdrawals.length; i++) {
BimodalLib.Withdrawal storage withdrawal = withdrawals[i];
if (withdrawal.eon.add(2) > ledger.lastSubmissionEon) {
break;
}
amount = amount.add(withdrawal.amount);
delete withdrawals[i];
}
}
function recoverOnlyParentChainFunds(
BimodalLib.Ledger storage ledger,
ERC20 token,
address holder
)
public
returns (
uint256 reclaimed
)
{
BimodalLib.Wallet storage wallet = ledger.walletBook[token][holder];
reclaimed = reclaimUncommittedDeposits(ledger, wallet).add(
reclaimFinalizedWithdrawal(ledger, wallet)
);
if (ledger.lastSubmissionEon > 0) {
BimodalLib.AmountAggregate storage eonWithdrawals = ledger
.confirmedWithdrawals[token][ledger
.lastSubmissionEon
.sub(1)
.mod(ledger.EONS_KEPT)];
BimodalLib.addToAggregate(
eonWithdrawals,
ledger.lastSubmissionEon.sub(1),
reclaimed
);
}
if (token != address(this)) {
require(ledger.tokenToTrail[token] != 0, "t");
require(token.transfer(holder, reclaimed), "f");
} else {
holder.transfer(reclaimed);
}
}
function recoverAllFunds(
BimodalLib.Ledger storage ledger,
ERC20 token,
address holder,
bytes32[2] checksums,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2] LR,
uint256[3] dummyPassiveMark
)
public
returns (
uint256 recovered
)
{
BimodalLib.Wallet storage wallet = ledger.walletBook[token][holder];
require(!wallet.recovered, "a");
wallet.recovered = true;
recovered = LR[1].sub(LR[0]);
recovered = recovered.add(reclaimUncommittedDeposits(ledger, wallet));
recovered = recovered.add(reclaimFinalizedWithdrawal(ledger, wallet));
if (ledger.lastSubmissionEon > 0) {
dummyPassiveMark[0] = ledger.lastSubmissionEon.sub(1);
} else {
dummyPassiveMark[0] = 0;
}
require(
ChallengeLib.verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
holder,
checksums,
trail,
dummyPassiveMark,
allotmentChain,
membershipChain,
values,
LR
),
"p"
);
BimodalLib.AmountAggregate storage eonWithdrawals = ledger
.confirmedWithdrawals[token][dummyPassiveMark[0].mod(
ledger.EONS_KEPT
)];
BimodalLib.addToAggregate(
eonWithdrawals,
dummyPassiveMark[0],
recovered
);
if (token != address(this)) {
require(ledger.tokenToTrail[token] != 0, "t");
require(token.transfer(holder, recovered), "f");
} else {
holder.transfer(recovered);
}
}
}
文件 14 的 19:RecoveryProxy.sol
pragma solidity ^0.4.24;
import "./BimodalProxy.sol";
import "./ERC20.sol";
import "./RecoveryLib.sol";
import "./SafeMathLib256.sol";
contract RecoveryProxy is BimodalProxy {
using SafeMathLib256 for uint256;
modifier onlyWhenContractPunished() {
require(
hasOutstandingChallenges() || hasMissedCheckpointSubmission(),
"f"
);
_;
}
function recoverOnlyParentChainFunds(ERC20 token, address holder)
public
onlyWhenContractPunished()
returns (uint256 reclaimed)
{
reclaimed = RecoveryLib.recoverOnlyParentChainFunds(
ledger,
token,
holder
);
}
function recoverAllFunds(
ERC20 token,
address holder,
bytes32[2] checksums,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2] LR,
uint256[3] dummyPassiveMark
) public onlyWhenContractPunished() returns (uint256 recovered) {
recovered = RecoveryLib.recoverAllFunds(
ledger,
token,
holder,
checksums,
trail,
allotmentChain,
membershipChain,
values,
LR,
dummyPassiveMark
);
}
}
文件 15 的 19:SafeMathLib256.sol
pragma solidity ^0.4.24;
library SafeMathLib256 {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, '+');
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, '-');
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, '*');
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, '/');
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, '%');
return a % b;
}
}
文件 16 的 19:SafeMathLib32.sol
pragma solidity ^0.4.24;
library SafeMathLib32 {
function add(uint32 a, uint32 b) internal pure returns (uint32) {
uint32 c = a + b;
require(c >= a, '+');
return c;
}
function sub(uint32 a, uint32 b) internal pure returns (uint32) {
require(b <= a, '-');
return a - b;
}
function mul(uint32 a, uint32 b) internal pure returns (uint32) {
if (a == 0) {
return 0;
}
uint32 c = a * b;
require(c / a == b, '*');
return c;
}
function div(uint32 a, uint32 b) internal pure returns (uint32) {
require(b > 0, '/');
return a / b;
}
function mod(uint32 a, uint32 b) internal pure returns (uint32) {
require(b > 0, '%');
return a % b;
}
}
文件 17 的 19:SafeMathLib64.sol
pragma solidity ^0.4.24;
library SafeMathLib64 {
function add(uint64 a, uint64 b) internal pure returns (uint64) {
uint64 c = a + b;
require(c >= a, '+');
return c;
}
function sub(uint64 a, uint64 b) internal pure returns (uint64) {
require(b <= a, '-');
return a - b;
}
function mul(uint64 a, uint64 b) internal pure returns (uint64) {
if (a == 0) {
return 0;
}
uint64 c = a * b;
require(c / a == b, '*');
return c;
}
function div(uint64 a, uint64 b) internal pure returns (uint64) {
require(b > 0, '/');
return a / b;
}
function mod(uint64 a, uint64 b) internal pure returns (uint64) {
require(b > 0, '%');
return a % b;
}
}
文件 18 的 19:WithdrawalLib.sol
pragma solidity ^0.4.24;
import "./BimodalLib.sol";
import "./ChallengeLib.sol";
import "./SafeMathLib256.sol";
library WithdrawalLib {
using SafeMathLib256 for uint256;
using BimodalLib for BimodalLib.Ledger;
event WithdrawalRequest(
address indexed token,
address indexed requestor,
uint256 amount
);
event WithdrawalConfirmation(
address indexed token,
address indexed requestor,
uint256 amount
);
function initWithdrawal(
BimodalLib.Ledger storage ledger,
ERC20 token,
address holder,
uint256 eon,
uint256 withdrawalAmount
) private
{
BimodalLib.Wallet storage entry = ledger.walletBook[token][holder];
uint256 balance = 0;
if (token != address(this)) {
require(ledger.tokenToTrail[token] != 0, "t");
balance = token.balanceOf(this);
} else {
balance = address(this).balance;
}
require(
ledger.getPendingWithdrawalsAtEon(token, eon).add(
withdrawalAmount
) <= balance,
"b"
);
entry.withdrawals.push(BimodalLib.Withdrawal(eon, withdrawalAmount));
ledger.addToRunningPendingWithdrawals(token, eon, withdrawalAmount);
ledger.appendOperationToEonAccumulator(
eon,
token,
holder,
BimodalLib.Operation.WITHDRAWAL,
withdrawalAmount
);
emit WithdrawalRequest(token, holder, withdrawalAmount);
}
function requestWithdrawal(
BimodalLib.Ledger storage ledger,
ERC20 token,
bytes32[2] checksums,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][2] lrPassiveMark,
uint256 withdrawalAmount
) public
{
uint256 available = lrPassiveMark[0][1].sub(lrPassiveMark[0][0]);
uint256 eon = ledger.currentEon();
uint256 pending = ledger.getWalletPendingWithdrawalAmountAtEon(
token,
msg.sender,
eon
);
require(available >= withdrawalAmount.add(pending), "b");
require(
ChallengeLib.verifyProofOfExclusiveAccountBalanceAllotment(
ledger,
token,
msg.sender,
checksums,
trail,
[eon.sub(1), lrPassiveMark[1][0], lrPassiveMark[1][1]],
allotmentChain,
membershipChain,
values,
lrPassiveMark[0]
),
"p"
);
initWithdrawal(ledger, token, msg.sender, eon, withdrawalAmount);
}
function requestAuthorizedWithdrawal(
BimodalLib.Ledger storage ledger,
ERC20 token,
uint256 withdrawalAmount,
uint256 expiry,
bytes32 r,
bytes32 s,
uint8 v
) public {
requestDelegatedWithdrawal(
ledger,
token,
msg.sender,
withdrawalAmount,
expiry,
r,
s,
v
);
}
function requestDelegatedWithdrawal(
BimodalLib.Ledger storage ledger,
ERC20 token,
address holder,
uint256 withdrawalAmount,
uint256 expiry,
bytes32 r,
bytes32 s,
uint8 v
) public
{
require(block.number <= expiry);
uint256 eon = ledger.currentEon();
uint256 pending = ledger.getWalletPendingWithdrawalAmountAtEon(
token,
holder,
eon
);
require(
ChallengeLib.verifyWithdrawalAuthorization(
token,
holder,
expiry,
withdrawalAmount.add(pending),
holder,
r,
s,
v
)
);
initWithdrawal(ledger, token, holder, eon, withdrawalAmount);
}
function confirmWithdrawal(
BimodalLib.Ledger storage ledger,
ERC20 token,
address recipient
)
public
returns (
uint256 amount
)
{
BimodalLib.Wallet storage entry = ledger.walletBook[token][recipient];
BimodalLib.Withdrawal[] storage withdrawals = entry.withdrawals;
uint256 eon = ledger.currentEon();
amount = 0;
uint32 i = 0;
for (i = 0; i < withdrawals.length; i++) {
BimodalLib.Withdrawal storage withdrawal = withdrawals[i];
if (withdrawal.eon.add(1) >= eon) {
break;
} else if (
withdrawal.eon.add(2) == eon &&
ledger.currentEra() < ledger.EXTENDED_BLOCKS_PER_EPOCH
) {
break;
}
amount = amount.add(withdrawal.amount);
}
for (uint32 j = 0; j < i && i < withdrawals.length; j++) {
withdrawals[j] = withdrawals[i];
i++;
}
withdrawals.length = withdrawals.length.sub(j);
ledger.deductFromRunningPendingWithdrawals(token, eon, eon, amount);
BimodalLib.AmountAggregate storage eonWithdrawals = ledger
.confirmedWithdrawals[token][eon.mod(ledger.EONS_KEPT)];
BimodalLib.addToAggregate(eonWithdrawals, eon, amount);
emit WithdrawalConfirmation(token, recipient, amount);
if (token != address(this)) {
require(ledger.tokenToTrail[token] != 0);
require(token.transfer(recipient, amount));
} else {
recipient.transfer(amount);
}
}
}
文件 19 的 19:WithdrawalProxy.sol
pragma solidity ^0.4.24;
import "./BimodalProxy.sol";
import "./ERC20.sol";
import "./WithdrawalLib.sol";
import "./SafeMathLib256.sol";
contract WithdrawalProxy is BimodalProxy {
using SafeMathLib256 for uint256;
modifier onlyWithConstantReimbursement(uint256 responseGas) {
require(
msg.value >= responseGas.mul(ledger.MIN_CHALLENGE_GAS_COST) &&
msg.value >= responseGas.mul(tx.gasprice),
"r"
);
ledger.operator.transfer(msg.value);
_;
}
function requestWithdrawal(
ERC20 token,
bytes32[2] checksums,
uint64 trail,
bytes32[] allotmentChain,
bytes32[] membershipChain,
uint256[] values,
uint256[2][2] lrPassiveMark,
uint256 withdrawalAmount
)
public
payable
onlyWithConstantReimbursement(100100)
onlyWhenContractUnpunished()
{
WithdrawalLib.requestWithdrawal(
ledger,
token,
checksums,
trail,
allotmentChain,
membershipChain,
values,
lrPassiveMark,
withdrawalAmount
);
}
function requestAuthorizedWithdrawal(
ERC20 token,
uint256 withdrawalAmount,
uint256 expiry,
bytes32 r,
bytes32 s,
uint8 v
) public onlyWhenContractUnpunished() {
WithdrawalLib.requestAuthorizedWithdrawal(
ledger,
token,
withdrawalAmount,
expiry,
r,
s,
v
);
}
function requestDelegatedWithdrawal(
ERC20 token,
address holder,
uint256 withdrawalAmount,
uint256 expiry,
bytes32 r,
bytes32 s,
uint8 v
) public onlyOperator() onlyWhenContractUnpunished() {
WithdrawalLib.requestDelegatedWithdrawal(
ledger,
token,
holder,
withdrawalAmount,
expiry,
r,
s,
v
);
}
function confirmWithdrawal(ERC20 token, address recipient)
public
onlyWhenContractUnpunished()
returns (uint256)
{
return WithdrawalLib.confirmWithdrawal(ledger, token, recipient);
}
}
{
"compilationTarget": {
"NOCUSTCommitChain.sol": "NOCUSTCommitChain"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"slot","type":"uint8"}],"name":"getPendingWithdrawalsAtSlot","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"getTokenTrail","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BLOCKS_PER_EPOCH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"SR","type":"address[2]"},{"name":"transferMembershipTrail","type":"uint64"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrDeltasPassiveMark","type":"uint256[2][3]"},{"name":"txSetRootChecksum","type":"bytes32[2]"},{"name":"txChain","type":"bytes32[]"}],"name":"answerTransferDeliveryChallengeWithProofOfActiveStateUpdateAgreement","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentEon","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hasMissedCheckpointSubmission","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DEPOSITS_KEPT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"},{"name":"eon","type":"uint256"}],"name":"getWalletPendingWithdrawalAmountAtEon","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"},{"name":"trail","type":"uint64"},{"name":"eon","type":"uint256"},{"name":"txSetRoot","type":"bytes32"},{"name":"deltas","type":"uint256[2]"},{"name":"attester","type":"address"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"}],"name":"verifyProofOfActiveStateUpdateAgreement","outputs":[{"name":"checksum","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"sender","type":"address"},{"name":"recipient","type":"address"}],"name":"getChallenge","outputs":[{"name":"","type":"uint8"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"addr","type":"address"},{"name":"eon","type":"uint256"}],"name":"getDepositsAtEon","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"}],"name":"registerERC20","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"checksums","type":"bytes32[2]"},{"name":"trail","type":"uint64"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrPassiveMark","type":"uint256[2][2]"},{"name":"withdrawalAmount","type":"uint256"}],"name":"requestWithdrawal","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"slot","type":"uint8"}],"name":"getDepositsAtSlot","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"EXTENDED_BLOCKS_PER_EPOCH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getServerContractStateVariables","outputs":[{"name":"parentChainAccumulator","type":"bytes32"},{"name":"lastSubmissionEon","type":"uint256"},{"name":"lastCheckpointRoot","type":"bytes32"},{"name":"isCheckpointSubmitted","type":"bool"},{"name":"missedCheckpointSubmission","type":"bool"},{"name":"liveChallenges","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"},{"name":"activeStateChecksum_passiveTransfersRoot","type":"bytes32[2]"},{"name":"trail","type":"uint64"},{"name":"eonPassiveMark","type":"uint256[3]"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"LR","type":"uint256[2]"}],"name":"verifyProofOfExclusiveAccountBalanceAllotment","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"eon","type":"uint256"}],"name":"getPendingWithdrawalsAtEon","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"addr","type":"address"},{"name":"slot","type":"uint8"}],"name":"getWalletDepositAggregateAtSlot","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"accumulator","type":"bytes32"},{"name":"merkleRoot","type":"bytes32"}],"name":"submitCheckpoint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"withdrawalAmount","type":"uint256"},{"name":"expiry","type":"uint256"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"}],"name":"requestAuthorizedWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"recipient","type":"address"}],"name":"confirmWithdrawal","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"slot","type":"uint8"}],"name":"getCheckpointAtSlot","outputs":[{"name":"","type":"uint256"},{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"},{"name":"checksums","type":"bytes32[2]"},{"name":"trail","type":"uint64"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"LR","type":"uint256[2]"},{"name":"dummyPassiveMark","type":"uint256[3]"}],"name":"recoverAllFunds","outputs":[{"name":"recovered","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"withdrawer","type":"address"},{"name":"markerEonAvailable","type":"uint256[2]"},{"name":"rs","type":"bytes32[2]"},{"name":"v","type":"uint8"}],"name":"slashWithdrawalWithProofOfMinimumAvailableBalance","outputs":[{"name":"","type":"uint256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"beneficiary","type":"address"},{"name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"SR","type":"address[2]"},{"name":"txSetRootChecksum","type":"bytes32[2]"},{"name":"senderTransferRecipientTrails","type":"uint64[3]"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrDeltasPassiveMarkDummyAmount","type":"uint256[2][4]"},{"name":"transferMembershipChain","type":"bytes32[]"}],"name":"challengeTransferDeliveryWithProofOfPassiveStateUpdate","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"}],"name":"getCurrentEonDepositsWithdrawals","outputs":[{"name":"currentEonDeposits","type":"uint256"},{"name":"currentEonWithdrawals","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"message","type":"bytes32"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"}],"name":"signedMessageECRECOVER","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"tokens","type":"address[2]"},{"name":"issuer","type":"address"},{"name":"transferMembershipTrail","type":"uint64"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"txChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrDeltasPassiveMark","type":"uint256[2][3]"},{"name":"balance","type":"uint256"},{"name":"txSetRootChecksumDummy","type":"bytes32[3]"}],"name":"answerSwapChallengeWithProofOfExclusiveBalanceAllotment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"trail","type":"uint64"}],"name":"getTokenAtTrail","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentEra","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hasOutstandingChallenges","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"issuer","type":"address"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrDeltasPassiveMark","type":"uint256[2][3]"},{"name":"rSrStxSetRootChecksum","type":"bytes32[6]"},{"name":"v","type":"uint8[2]"}],"name":"answerStateUpdateChallenge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"SR","type":"address[2]"},{"name":"nonceAmount","type":"uint256[2]"},{"name":"trails","type":"uint64[3]"},{"name":"chain","type":"bytes32[]"},{"name":"deltas","type":"uint256[2]"},{"name":"rsTxSetRoot","type":"bytes32[3]"},{"name":"v","type":"uint8"}],"name":"challengeTransferDeliveryWithProofOfActiveStateUpdateAgreement","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"allotmentTrail","type":"uint64"},{"name":"membershipTrail","type":"uint64"},{"name":"node","type":"bytes32"},{"name":"root","type":"bytes32"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"value","type":"uint256[]"},{"name":"LR","type":"uint256[2]"}],"name":"verifyProofOfExclusiveBalanceAllotment","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"eonNumber","type":"uint256"},{"name":"token","type":"address"}],"name":"getServerContractLedgerStateVariables","outputs":[{"name":"pendingWithdrawals","type":"uint256"},{"name":"confirmedWithdrawals","type":"uint256"},{"name":"deposits","type":"uint256"},{"name":"totalBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"},{"name":"expiry","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"attester","type":"address"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"}],"name":"verifyWithdrawalAuthorization","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"txSetRoot","type":"bytes32"},{"name":"trail","type":"uint64"},{"name":"deltas","type":"uint256[2]"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"}],"name":"challengeStateUpdateWithProofOfActiveStateUpdateAgreement","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"allotmentTrail","type":"uint64"},{"name":"node","type":"bytes32"},{"name":"root","type":"bytes32"},{"name":"chainValues","type":"bytes32[]"},{"name":"LR","type":"uint256[2]"}],"name":"verifyProofOfPassiveDelivery","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"genesis","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"eon","type":"uint256"}],"name":"getLiveChallenges","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BLOCKS_PER_EON","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"EONS_KEPT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"}],"name":"getClientContractStateVariables","outputs":[{"name":"latestCheckpointEonNumber","type":"uint256"},{"name":"latestCheckpointsMerkleRoots","type":"bytes32[5]"},{"name":"latestCheckpointsLiveChallenges","type":"uint256[5]"},{"name":"currentEonDeposits","type":"uint256"},{"name":"previousEonDeposits","type":"uint256"},{"name":"secondPreviousEonDeposits","type":"uint256"},{"name":"pendingWithdrawals","type":"uint256[2][]"},{"name":"holderBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"SR","type":"address[2]"},{"name":"transferMembershipTrail","type":"uint64"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrPassiveMarkPositionNonce","type":"uint256[2][3]"},{"name":"checksums","type":"bytes32[2]"},{"name":"txChainValues","type":"bytes32[]"}],"name":"answerTransferDeliveryChallengeWithProofOfPassiveStateUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"}],"name":"getIsWalletRecovered","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"trail","type":"uint256"},{"name":"chain","type":"bytes32[]"},{"name":"node","type":"bytes32"},{"name":"merkleRoot","type":"bytes32"}],"name":"verifyProofOfMembership","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"checksums","type":"bytes32[2]"},{"name":"trail","type":"uint64"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"value","type":"uint256[]"},{"name":"lrDeltasPassiveMark","type":"uint256[2][3]"},{"name":"rsTxSetRoot","type":"bytes32[3]"},{"name":"v","type":"uint8"}],"name":"challengeStateUpdateWithProofOfExclusiveBalanceAllotment","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"tokens","type":"address[2]"},{"name":"senderTransferRecipientTrails","type":"uint64[3]"},{"name":"allotmentChain","type":"bytes32[]"},{"name":"membershipChain","type":"bytes32[]"},{"name":"txChain","type":"bytes32[]"},{"name":"values","type":"uint256[]"},{"name":"lrDeltasPassiveMark","type":"uint256[2][3]"},{"name":"sellBuyBalanceNonce","type":"uint256[4]"},{"name":"txSetRootChecksumDummy","type":"bytes32[3]"}],"name":"challengeSwapEnactmentWithProofOfActiveStateUpdateAgreement","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"MIN_CHALLENGE_GAS_COST","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"},{"name":"withdrawalAmount","type":"uint256"},{"name":"expiry","type":"uint256"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"v","type":"uint8"}],"name":"requestDelegatedWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"}],"name":"recoverOnlyParentChainFunds","outputs":[{"name":"reclaimed","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"lastSubmissionEon","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"slot","type":"uint8"}],"name":"getConfirmedWithdrawalsAtSlot","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"slot","type":"uint8"}],"name":"getParentChainAccumulatorAtSlot","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"blocksPerEon","type":"uint256"},{"name":"operator","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"eon","type":"uint256"},{"indexed":false,"name":"merkleRoot","type":"bytes32"}],"name":"CheckpointSubmission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"requestor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"requestor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalConfirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"recipient","type":"address"},{"indexed":true,"name":"sender","type":"address"}],"name":"ChallengeIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"account","type":"address"},{"indexed":true,"name":"eon","type":"uint256"},{"indexed":false,"name":"trail","type":"uint64"},{"indexed":false,"name":"allotmentChain","type":"bytes32[]"},{"indexed":false,"name":"membershipChain","type":"bytes32[]"},{"indexed":false,"name":"values","type":"uint256[]"},{"indexed":false,"name":"lrDeltasPassiveMark","type":"uint256[2][3]"},{"indexed":false,"name":"activeStateChecksum","type":"bytes32"},{"indexed":false,"name":"passiveChecksum","type":"bytes32"},{"indexed":false,"name":"r","type":"bytes32"},{"indexed":false,"name":"s","type":"bytes32"},{"indexed":false,"name":"v","type":"uint8"}],"name":"StateUpdate","type":"event"}]