public static object withdraw(byte[] walletId, byte[] tokenAddress, byte[] receiver, BigInteger amount, byte[] callingScriptHash)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal, not byte32");
            BasicMethods.assert(BasicMethods._isLegalAddress(tokenAddress), "tokenAddress is illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(receiver), "receiver address is illegal");
            BasicMethods.assert(amount >= 0, "amount is less than zero");
            BasicMethods.assert(Runtime.CheckWitness(receiver), "CheckWitness failed");
            BigInteger[] tokenValues = getTokenWithdraw();
            if (tokenAddress.Equals(LedgerStruct.NeoAddress))
            {
                BasicMethods.assert(amount >= tokenValues[0], "withdrawn Neo is more than declared");
            }
            else if (tokenAddress.Equals(LedgerStruct.GasAddress))
            {
                BasicMethods.assert(amount >= tokenValues[1], "withdrawn Gas is more than declared");
            }

            _whenNotPaused();
            _onlyOperator(walletId, callingScriptHash);
            _onlyWalletOwner(walletId, receiver);

            BasicMethods.assert(_updateBalance(walletId, tokenAddress, amount, getStandardMathOperation().sub), "updateBalance failed");
            BasicMethods.assert(_withdrawToken(tokenAddress, receiver, amount), "withdrawToken failed");
            WithdrawFromWallet(walletId, tokenAddress, receiver, amount);
            return(true);
        }
 public static bool _checkCoSignatures(LedgerStruct.Channel _c, byte[] _h, byte[][] pubKeys, byte[][] _sig)
 {
     BasicMethods.assert(BasicMethods._isByte32(_h), "_fromLedgerAddr parameter error");
     BasicMethods.assert(pubKeys.Length == 2, "Illegal pubKeys length");
     BasicMethods.assert(_sig.Length == 2, "_fromLedgerAddr parameter error");
     return(_isPeerVer3(_c, _h, pubKeys, _sig));
 }
        public static byte[][] getWalletOwners(byte[] walletId)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal");
            Wallet w = getWallet(walletId);

            return(w.owners);
        }
        public static byte[] getProposedNewOperator(byte[] walletId)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal");
            Wallet w = getWallet(walletId);

            return(w.proposedNewOperator);
        }
        public static bool intendSettleMockSet(byte[] _channelId, byte[] _peerFrom, BigInteger _seqNum, BigInteger _transferOut, byte[] _nextPayIdListHash, BigInteger _lastPayResolveDeadline, BigInteger _pendingPayOut)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_peerFrom), "_peerFrom illegal");
            BasicMethods.assert(_seqNum >= 0, "_seqNum smaller than zero");
            BasicMethods.assert(_transferOut >= 0, "_transferOut smaller than zero");
            BasicMethods.assert(BasicMethods._isByte32(_nextPayIdListHash), "_nextPayIdListHash illegal");
            BasicMethods.assert(_lastPayResolveDeadline >= 0, "_lastPayResolveDeadline smaller than zero");
            BasicMethods.assert(_pendingPayOut >= 0, "_pendingPayOut smaller than zero");

            LedgerStruct.Channel c = LedgerStruct.getChannelMap(_channelId);
            byte peerFromId        = LedgerChannel._getPeerId(c, _peerFrom);

            BasicMethods.assert(peerFromId == 0 || peerFromId == 1, "peerFromId illegal");
            LedgerStruct.PeerProfile[] peerProfiles = c.peerProfiles;
            LedgerStruct.PeerProfile   peerProfile  = peerProfiles[peerFromId];
            LedgerStruct.PeerState     state        = peerProfile.state;

            state.seqNum                 = _seqNum;
            state.transferOut            = _transferOut;
            state.nextPayIdListHash      = _nextPayIdListHash;
            state.lastPayResolveDeadline = _lastPayResolveDeadline;
            state.pendingPayOut          = _pendingPayOut;
            peerProfile.state            = state;
            peerProfiles[peerFromId]     = peerProfile;
            c.peerProfiles               = peerProfiles;

            c = _updateOverallStatesByIntendState(c);
            LedgerStruct.setChannelMap(_channelId, c);
            setTmpChannelId(_channelId);
            return(true);
        }
        public static bool snapshotStatesMockSet(byte[][] _channelIds, byte[][] _peerFroms, BigInteger[] _seqNums, BigInteger[] _transferOuts, BigInteger[] _pendingPayOuts)
        {
            BasicMethods.assert(_channelIds.Length == _peerFroms.Length &&
                                _peerFroms.Length == _seqNums.Length &&
                                _seqNums.Length == _transferOuts.Length &&
                                _transferOuts.Length == _pendingPayOuts.Length,
                                "Parameter length not the same");

            for (int i = 0; i < _channelIds.Length; i++)
            {
                BasicMethods.assert(BasicMethods._isByte32(_channelIds[i]), "_channelIds " + i + " illegal");
                BasicMethods.assert(BasicMethods._isLegalAddress(_peerFroms[i]), "_peerFroms " + i + " illegal");
                BasicMethods.assert(_seqNums[i] >= 0, "_seqNums " + i + " illegal");
                BasicMethods.assert(_transferOuts[i] >= 0, "_transferOuts " + i + " illegal");
                BasicMethods.assert(_pendingPayOuts[i] >= 0, "_pendingPayOuts " + i + " illegal");

                LedgerStruct.Channel c = LedgerStruct.getChannelMap(_channelIds[i]);
                byte peerFromId        = LedgerChannel._getPeerId(c, _peerFroms[i]);
                LedgerStruct.PeerProfile[] peerProfiles = c.peerProfiles;
                LedgerStruct.PeerProfile   peerProfile  = peerProfiles[peerFromId];
                LedgerStruct.PeerState     state        = peerProfile.state;
                state.seqNum             = _seqNums[i];
                state.transferOut        = _transferOuts[i];
                state.pendingPayOut      = _pendingPayOuts[i];
                peerProfile.state        = state;
                peerProfiles[peerFromId] = peerProfile;
                c.peerProfiles           = peerProfiles;
                LedgerStruct.setChannelMap(_channelIds[i], c);
            }
            setTmpChannelIdSet(_channelIds);
            return(true);
        }
        public static object transferToCelerWallet(byte[] invoker, byte[] from, byte[] walletAddr, byte[] walletId, BigInteger value)
        {
            BasicMethods.assert(BasicMethods._isLegalAddress(invoker), "invoker or spender address is illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(from), "from address is illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(walletAddr), "to address is illegal");
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId is not byte32");
            BasicMethods.assert(value >= 0, "amount is less than 0");

            BasicMethods.assert(Runtime.CheckWitness(invoker), "CheckWitness failed");

            BigInteger approvedBalance = allowance(from, invoker);

            BasicMethods.assert(value <= approvedBalance, "value is greater than allowance of spender allowed to spend");
            Storage.Put(Storage.CurrentContext, ApprovePrefix.Concat(from).Concat(invoker), approvedBalance - value);
            Approved(from, invoker, allowance(from, invoker));

            BigInteger fromBalance = balanceOf(from);

            BasicMethods.assert(value <= fromBalance, "value is greater than the owner's balance");
            Storage.Put(Storage.CurrentContext, BalancePrefix.Concat(from), fromBalance - value);
            Transferred(from, walletAddr, value);


            byte[] celerWalletHash      = Storage.Get(Storage.CurrentContext, CelerWalletHashKey);
            byte[] nep5Hash             = Storage.Get(Storage.CurrentContext, NEP5HashKey);
            DynamicCallContract dyncall = (DynamicCallContract)celerWalletHash.ToDelegate();

            BasicMethods.assert((bool)dyncall("depositNEP5", new object[] { invoker, walletId, nep5Hash, value }), "transfer NEP5 token to the to the celer wallet failed");

            return(true);
        }
        public static bool intendSettle(byte[] _signedSimplexStateArray)
        {
            byte[] _channelId = getTmpChannelId();
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");

            LedgerStruct.Channel c = LedgerStruct.getChannelMap(_channelId);
            IntendSettleEvent(_channelId, LedgerChannel._getStateSeqNums(c));
            return(true);
        }
        public static bool intendWithdraw(byte[] _channelId, BigInteger _amount, byte[] _recipientChannelId)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
            BasicMethods.assert(_amount >= 0, "_amount smaller than zero");
            BasicMethods.assert(BasicMethods._isByte32(_recipientChannelId), "_recipientChannelId illegal");

            LedgerStruct.Channel c = LedgerStruct.getChannelMap(_channelId);
            IntendWithdrawEvent(_channelId, c.withdrawIntent.receiver, _amount);
            return(true);
        }
 public static bool snapshotStates(byte[] _signedSimplexStateArray)
 {
     byte[][] tmpChannelIds = getTmpChannelIdSet();
     for (int i = 0; i < tmpChannelIds.Length; i++)
     {
         BasicMethods.assert(BasicMethods._isByte32(tmpChannelIds[i]), "tmpChannelIds " + i + " illegal");
         LedgerStruct.Channel c = LedgerStruct.getChannelMap(tmpChannelIds[i]);
         SnapshotStatesEvent(tmpChannelIds[i], LedgerChannel._getStateSeqNums(c));
     }
     return(true);
 }
        public static object transferOperatorship(byte[] walletId, byte[] newOperator, byte[] callingScriptHash)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal, not byte32");
            BasicMethods.assert(BasicMethods._isLegalAddress(newOperator), "newOperator address is illegal");
            // no need to checkwitness since _onlyOperator has already done it

            _whenNotPaused();
            _onlyOperator(walletId, callingScriptHash);
            _changeOperator(walletId, newOperator);
            return(true);
        }
        public static byte[] getProposedNewOperator(byte[] walletId)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal");
            Wallet w = new Wallet();

            byte[] walletBs = Storage.Get(Storage.CurrentContext, WalletsPrefix.Concat(walletId));
            if (walletBs.Length > 0)
            {
                w = Helper.Deserialize(walletBs) as Wallet;
            }
            return(w.theOperator);
        }
        public static object depositNEO(byte[] walletId)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId is not byte32");
            PbEntity.TokenType token = PbEntity.getStandardTokenType();
            BigInteger         value = LedgerStruct.getTransactionValue(token.NEO, ExecutionEngine.ExecutingScriptHash);

            BasicMethods.assert(value >= 0, "amount is less than zero");
            _whenNotPaused();
            BasicMethods.assert(_updateBalance(walletId, LedgerStruct.NeoAddress, value, getStandardMathOperation().add), "updateBalance failed");

            DepositToWallet(walletId, LedgerStruct.NeoAddress, value);
            return(true);
        }
        public static BigInteger getBalance(byte[] walletId, byte[] tokenAddress)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(tokenAddress), "tokenAddress is illegal");
            byte[] wBalanceBs = Storage.Get(Storage.CurrentContext, WalletsPrefix.Concat(WalletsBalancesPrefix).Concat(walletId));
            Map <byte[], BigInteger> wBalanceMap = Helper.Deserialize(wBalanceBs) as Map <byte[], BigInteger>;

            if (wBalanceMap.HasKey(tokenAddress))
            {
                return(wBalanceMap[tokenAddress]);
            }
            return(0);
        }
        public static BigInteger[] getPayInfo(byte[] payId)
        {
            BasicMethods.assert(BasicMethods._isByte32(payId), "payId invalid");
            byte[]  payInfoBs = Storage.Get(Storage.CurrentContext, PayInfoPrefix.Concat(payId));
            PayInfo payInfo   = new PayInfo();

            if (payInfoBs.Length > 0)
            {
                payInfo = Helper.Deserialize(payInfoBs) as PayInfo;
            }
            return(new BigInteger[2] {
                payInfo.amount, payInfo.resolveDeadline
            });
        }
    public static LedgerStruct.Channel _importChannelMigrationArgs(LedgerStruct.Channel _c, byte[] _fromLedgerAddr, byte[] _channelId)
    {
        BasicMethods.assert(BasicMethods._isLegalAddress(_fromLedgerAddr), "invalid contract address");
        BasicMethods.assert(BasicMethods._isByte32(_channelId), "invalid _channelId");

        DynamicCallContract dyncall = (DynamicCallContract)_fromLedgerAddr.ToDelegate();

        LedgerStruct.ChannelMigrationArgs args = (LedgerStruct.ChannelMigrationArgs)dyncall("getChannelMigrationArgs", new object[] { _channelId });
        _c.disputeTimeout = args.disputeTimeout;
        PbEntity.TokenInfo token = new PbEntity.TokenInfo();
        token.tokenType = args.tokenType;
        token.address   = args.tokenAddress;
        _c.token        = token;
        _c.cooperativeWithdrawSeqNum = args.cooperativeWithdrawSeqNum;
        return(_c);
    }
        public static bool getProposalVote(byte[] walletId, byte[] owner)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(owner), "owner address is not length of 20 bytes");
            _onlyWalletOwner(walletId, owner);
            // wpvBs means Wallet Proposal Votes ByteS
            byte[]             wpvBs = Storage.Get(Storage.CurrentContext, WalletsProposalVotesPrefix.Concat(walletId));
            Map <byte[], bool> wpv   = new Map <byte[], bool>();

            if (wpvBs.Length > 0)
            {
                wpv = Helper.Deserialize(wpvBs) as Map <byte[], bool>;
                return(wpv[owner]);
            }
            return(false);
        }
        public static object withdraw(byte[] walletId, byte[] tokenAddress, byte[] receiver, BigInteger amount)
        {
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal, not byte32");
            BasicMethods.assert(BasicMethods._isLegalAddress(tokenAddress), "tokenAddress is illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(receiver), "receiver address is illegal");
            BasicMethods.assert(amount > 0, "amount is less than zero");
            //assert(Runtime.CheckWitness(receiver), "CheckWitness failed");

            _whenNotPaused();
            _onlyOperator(walletId);
            _onlyWalletOwner(walletId, receiver);

            BasicMethods.assert(_updateBalance(walletId, tokenAddress, amount, "sub"), "updateBalance failed");
            BasicMethods.assert(_withdrawToken(tokenAddress, receiver, amount), "withdrawToken failed");
            WithdrawFromWallet(walletId, tokenAddress, receiver, amount);
            return(true);
        }
 public static bool confirmSettle(byte[] _channelId)
 {
     BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
     LedgerStruct.Channel       c       = LedgerStruct.getChannelMap(_channelId);
     LedgerStruct.SettleBalance balance = LedgerChannel._validateSettleBalance(c);
     if (balance.isSettled != 1)
     {
         c = _resetDuplexState(c);
         ConfirmSettleFailEvent(_channelId);
         return(false);
     }
     LedgerStruct.ChannelStatus channelStatus = LedgerStruct.getStandardChannelStatus();
     c = _updateChannelStatus(c, channelStatus.Closed);
     LedgerStruct.setChannelMap(_channelId, c);
     ConfirmSettleEvent(_channelId, balance.balance);
     return(true);
 }
        public static object depositNEP5(byte[] invoker, byte[] walletId, byte[] tokenAddress, BigInteger amount)
        {
            BasicMethods.assert(Runtime.CheckWitness(invoker), "CheckWitness failed");
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId is not byte32");
            BasicMethods.assert(BasicMethods._isLegalAddress(tokenAddress), "tokenAddress is not byte20");
            BasicMethods.assert(amount >= 0, "amount is less than zero");

            _whenNotPaused();

            BasicMethods.assert(_updateBalance(walletId, tokenAddress, amount, getStandardMathOperation().add), "updateBalance failed");
            byte[]       thisContract = ExecutionEngine.ExecutingScriptHash;
            NEP5Contract dyncall      = (NEP5Contract)tokenAddress.ToDelegate();
            bool         res          = (bool)dyncall("transfer", new object[] { invoker, thisContract, amount });

            BasicMethods.assert(res, "transfer NEP5 tokens failed");

            DepositToWallet(walletId, tokenAddress, amount);
            return(true);
        }
        public static bool intendWithdrawMockSet(byte[] _channelId, BigInteger _amount, byte[] _recipientChannelId, byte[] _receiver)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
            BasicMethods.assert(_amount >= 0, "_amount smaller than zero");
            BasicMethods.assert(BasicMethods._isByte32(_recipientChannelId), "_recipientChannelId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_receiver), "_receiver illegal");

            LedgerStruct.Channel        c = LedgerStruct.getChannelMap(_channelId);
            LedgerStruct.WithdrawIntent withdrawIntent = c.withdrawIntent;

            withdrawIntent.receiver           = _receiver;
            withdrawIntent.amount             = _amount;
            withdrawIntent.requestTime        = Blockchain.GetHeight();
            withdrawIntent.recipientChannelId = _recipientChannelId;
            c.withdrawIntent = withdrawIntent;
            setTmpChannelId(_channelId);
            LedgerStruct.setChannelMap(_channelId, c);
            return(true);
        }
        public static object transferToWallet(byte[] fromWalletId, byte[] toWalletId, byte[] tokenAddress, byte[] receiver, BigInteger amount, byte[] callingScriptHash)
        {
            BasicMethods.assert(BasicMethods._isByte32(fromWalletId), "fromWalletId illegal, not byte32");
            BasicMethods.assert(BasicMethods._isByte32(toWalletId), "toWalletId illegal, not byte32");
            BasicMethods.assert(BasicMethods._isLegalAddress(tokenAddress), "tokenAddress is illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(receiver), "receiver address is illegal");
            BasicMethods.assert(amount >= 0, "amount is less than zero");
            BasicMethods.assert(Runtime.CheckWitness(receiver), "CheckWitness failed");

            _whenNotPaused();
            _onlyOperator(fromWalletId, callingScriptHash);
            _onlyWalletOwner(fromWalletId, receiver);
            _onlyWalletOwner(toWalletId, receiver);

            BasicMethods.assert(_updateBalance(fromWalletId, tokenAddress, amount, getStandardMathOperation().sub), "sub balance in from wallet failed");
            BasicMethods.assert(_updateBalance(toWalletId, tokenAddress, amount, getStandardMathOperation().add), "add balance in to wallet failed");

            TransferToWallet(fromWalletId, toWalletId, tokenAddress, receiver, amount);
            return(true);
        }
        public static object setPayDeadline(byte[] invoker, byte[] payHash, BigInteger deadline)
        {
            BasicMethods.assert(BasicMethods._isByte32(payHash), "invalid hash");
            BasicMethods.assert(BasicMethods._isLegalAddress(invoker), "invalid address");
            BasicMethods.assert(deadline >= 0, "deadline is less than zero");
            BasicMethods.assert(Runtime.CheckWitness(invoker), "CheckWitness failed");

            byte[]  payId     = calculatePayId(payHash, invoker);
            byte[]  payInfoBs = Storage.Get(Storage.CurrentContext, PayInfoPrefix.Concat(payId));
            PayInfo payInfo   = new PayInfo();

            if (payInfoBs.Length > 0)
            {
                payInfo = Helper.Deserialize(payInfoBs) as PayInfo;
            }
            payInfo.resolveDeadline = deadline;
            Storage.Put(Storage.CurrentContext, PayInfoPrefix.Concat(payId), Helper.Serialize(payInfo));

            PayInfoUpdate(payId, payInfo.amount, deadline);

            return(true);
        }
    public static byte[] migrateChannelToInner(byte[] sender, LedgerStruct.Ledger _self, byte[][] pubKeys, byte[] _migrationRequest)
    {
        BasicMethods.assert(BasicMethods._isLegalAddress(sender), "sender illegal");
        PbChain.ChannelMigrationRequest migrationRequest =
            (PbChain.ChannelMigrationRequest)Neo.SmartContract.Framework.Helper.Deserialize(_migrationRequest);
        PbEntity.ChannelMigrationInfo migrationInfo =
            (PbEntity.ChannelMigrationInfo)Neo.SmartContract.Framework.Helper.Deserialize(migrationRequest.channelMigrationInfo);
        byte[] channelId = migrationInfo.channelId;
        BasicMethods.assert(BasicMethods._isByte32(channelId), "channelId illegal");
        LedgerStruct.Channel c = LedgerStruct.getChannelMap(channelId);
        byte[] toLedgerAddr    = migrationInfo.toLedgerAddress;

        LedgerStruct.ChannelStatus channelStatus = LedgerStruct.getStandardChannelStatus();
        BasicMethods.assert(
            c.status == channelStatus.Operable ||
            c.status == channelStatus.Settling, "status illegal"
            );
        byte[] h = Hash256(migrationRequest.channelMigrationInfo);
        // use Channel Library instead

        BasicMethods.assert(LedgerChannel._checkCoSignatures(c, h, pubKeys, migrationRequest.sigs), "Check co-sigs failed");
        BasicMethods.assert(migrationInfo.fromLedgerAddress.Equals(ExecutionEngine.ExecutingScriptHash), "From ledger address is not this");
        BasicMethods.assert(toLedgerAddr.Equals(sender), "To ledger address is not msg.sender");
        BasicMethods.assert(Blockchain.GetHeight() <= migrationInfo.migrationDeadline, "Passed migration deadline");

        c            = LedgerOperation._updateChannelStatus(c, channelStatus.Migrated);
        c.migratedTo = toLedgerAddr;
        LedgerStruct.setChannelMap(channelId, c);
        MigrateChannelToEvent(channelId, toLedgerAddr);

        byte[] celerWallet = _self.celerWallet;

        NEP5Contract dyncall = (NEP5Contract)celerWallet.ToDelegate();

        Object[] args = new object[] { channelId, toLedgerAddr };
        dyncall("transferOperatorship", args);

        return(channelId);
    }
        public static bool confirmWithdraw(byte[] _channelId)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");

            LedgerStruct.Channel        c = LedgerStruct.getChannelMap(_channelId);
            LedgerStruct.WithdrawIntent withdrawIntent = c.withdrawIntent;
            byte[]     receiver = BasicMethods.clone(withdrawIntent.receiver);
            BigInteger amount   = withdrawIntent.amount;

            byte[] recipientChannelId = BasicMethods.clone(withdrawIntent.recipientChannelId);
            withdrawIntent.receiver           = null;
            withdrawIntent.amount             = 0;
            withdrawIntent.requestTime        = 0;
            withdrawIntent.recipientChannelId = null;
            c.withdrawIntent = withdrawIntent;
            c = LedgerChannel._addWithdrawal(c, receiver, amount);
            LedgerStruct.setChannelMap(_channelId, c);
            LedgerStruct.BalanceMap balanceMap = LedgerChannel.getBalanceMapInner(c);
            ConfirmWithdrawEvent(_channelId, amount, receiver, recipientChannelId, balanceMap.deposits, balanceMap.withdrawals);

            return(true);
        }
    public static LedgerStruct.Channel _importPeersMigrationInfo(LedgerStruct.Channel _c, byte[] _fromLedgerAddr, byte[] _channelId)
    {
        BasicMethods.assert(BasicMethods._isLegalAddress(_fromLedgerAddr), "invalid contract address");
        BasicMethods.assert(BasicMethods._isByte32(_channelId), "invalid _channelId");
        object[]            input   = new object[] { _channelId };
        DynamicCallContract dyncall = (DynamicCallContract)_fromLedgerAddr.ToDelegate();

        LedgerStruct.PeersMigrationInfo args = (LedgerStruct.PeersMigrationInfo)dyncall("getPeersMigrationInfo", input);
        byte[][]     peerAddr      = args.peerAddr;
        BigInteger[] deposit       = args.deposit;
        BigInteger[] withdrawal    = args.withdrawal;
        BigInteger[] seqNum        = args.seqNum;
        BigInteger[] transferOut   = args.transferOut;
        BigInteger[] pendingPayout = args.pendingPayout;
        LedgerStruct.PeerProfile[] peerProfiles = _c.peerProfiles;
        for (int i = 0; i < 2; i++)
        {
            LedgerStruct.PeerProfile originalPeerProfile = peerProfiles[i];
            LedgerStruct.PeerState   originaPeerState    = originalPeerProfile.state;
            LedgerStruct.PeerState   peerState           = new LedgerStruct.PeerState
            {
                seqNum                 = seqNum[i],
                transferOut            = transferOut[i],
                nextPayIdListHash      = originaPeerState.nextPayIdListHash,
                lastPayResolveDeadline = originaPeerState.lastPayResolveDeadline,
                pendingPayOut          = pendingPayout[i]
            };
            LedgerStruct.PeerProfile peerProfile = new LedgerStruct.PeerProfile()
            {
                peerAddr   = peerAddr[i],
                deposit    = deposit[i],
                withdrawal = withdrawal[i],
                state      = peerState
            };
            peerProfiles[i] = peerProfile;
        }
        return(_c);
    }
        public static object proposeNewOperator(byte[] invoker, byte[] walletId, byte[] newOperator)
        {
            BasicMethods.assert(Runtime.CheckWitness(invoker), "CheckWitness failed");
            BasicMethods.assert(BasicMethods._isByte32(walletId), "walletId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(newOperator), "new operator is not address");

            _onlyWalletOwner(walletId, invoker);

            Wallet w = getWallet(walletId);

            // wpvBs means Wallet Proposal Votes ByteS
            byte[]             wpvBs = Storage.Get(Storage.CurrentContext, WalletsPrefix.Concat(WalletsProposalVotesPrefix).Concat(walletId));
            Map <byte[], bool> wpv   = new Map <byte[], bool>();

            if (wpvBs.Length > 0)
            {
                wpv = Helper.Deserialize(wpvBs) as Map <byte[], bool>;
            }

            if (newOperator != w.proposedNewOperator)
            {
                wpv = _clearVotes(w, wpv);
                w.proposedNewOperator = newOperator;
            }
            wpv[invoker] = true;

            if (_checkAllVotes(w, wpv))
            {
                _changeOperator(walletId, newOperator);
                wpv = _clearVotes(w, wpv);
            }

            Storage.Put(Storage.CurrentContext, WalletsPrefix.Concat(walletId), Helper.Serialize(w));
            Storage.Put(Storage.CurrentContext, WalletsPrefix.Concat(WalletsProposalVotesPrefix).Concat(walletId), Helper.Serialize(wpv));

            ProposeNewOperator(walletId, newOperator, invoker);
            return(true);
        }
        public static bool openChannelMockSet(byte[] _channelId, BigInteger _disputeTimeout, byte[] _tokenAddress, byte _tokenType, byte[][] _peerAddrs, BigInteger[] _deposits)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_tokenAddress), "_channelId illegal");
            BasicMethods.assert(_tokenType >= 0 && _tokenType <= 3, "_tokenType illegal");
            BasicMethods.assert(_peerAddrs.Length == 2, "_peerAddrs length illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_peerAddrs[0]), "_peerAddrs 0 illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_peerAddrs[1]), "_peerAddrs 1 illegal");
            BasicMethods.assert(_deposits.Length == 2, "_deposits length illegal");
            BasicMethods.assert(_deposits[0] >= 0, "_deposits 0 illegal");
            BasicMethods.assert(_deposits[1] >= 0, "_deposits 1 illegal");

            setTmpChannelId(_channelId);

            LedgerStruct.Channel c = LedgerStruct.getChannelMap(_channelId);
            c.disputeTimeout = _disputeTimeout;
            LedgerStruct.ChannelStatus channelStatus = LedgerStruct.getStandardChannelStatus();
            c = LedgerOperation._updateChannelStatus(c, channelStatus.Operable);
            PbEntity.TokenInfo token = new PbEntity.TokenInfo()
            {
                address   = _tokenAddress,
                tokenType = _tokenType
            };
            c.token = token;

            LedgerStruct.PeerProfile[] peerProfiles = c.peerProfiles;
            LedgerStruct.PeerProfile   peerProfile0 = peerProfiles[0];
            LedgerStruct.PeerProfile   peerProfile1 = peerProfiles[1];
            peerProfile0.peerAddr = _peerAddrs[0];
            peerProfile0.deposit  = _deposits[0];
            peerProfile1.peerAddr = _peerAddrs[1];
            peerProfile1.deposit  = _deposits[1];
            peerProfiles[0]       = peerProfile0;
            peerProfiles[1]       = peerProfile1;
            c.peerProfiles        = peerProfiles;
            LedgerStruct.setChannelMap(_channelId, c);
            return(true);
        }
        public static bool vetoWithdraw(byte[] _channelId, byte[] _sender)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_sender), "_sender illegal");
            BasicMethods.assert(Runtime.CheckWitness(_sender), "_sender check witness failed");

            LedgerStruct.Channel       c             = LedgerStruct.getChannelMap(_channelId);
            LedgerStruct.ChannelStatus channelStatus = LedgerStruct.getStandardChannelStatus();
            BasicMethods.assert(c.status == channelStatus.Operable, "Channel status error");
            LedgerStruct.WithdrawIntent withdrawIntent = c.withdrawIntent;
            byte[] receiver = withdrawIntent.receiver;
            BasicMethods.assert(receiver.ToBigInteger() != 0, "No pending withdraw intent");
            BasicMethods.assert(LedgerChannel._isPeer(c, _sender), "msg.sender is not peer");

            withdrawIntent.receiver           = null;
            withdrawIntent.amount             = 0;
            withdrawIntent.requestTime        = 0;
            withdrawIntent.recipientChannelId = null;
            c.withdrawIntent = withdrawIntent;
            LedgerStruct.setChannelMap(_channelId, c);
            VetoWithdrawEvent(_channelId);
            return(true);
        }
        public static bool deposit(byte[] _channelId, byte[] _receiver, BigInteger _transferFromAmount)
        {
            BasicMethods.assert(BasicMethods._isByte32(_channelId), "_channelId illegal");
            BasicMethods.assert(BasicMethods._isLegalAddress(_receiver), "_receiver illegal");
            BasicMethods.assert(_transferFromAmount >= 0, "_transferFromAmount illegal");

            LedgerStruct.Channel c = LedgerStruct.getChannelMap(_channelId);
            byte rid = LedgerChannel._getPeerId(c, _receiver);

            BasicMethods.assert(rid == 0 || rid == 1, "rid illegal");
            PbEntity.TokenInfo token  = c.token;
            BigInteger         value  = LedgerStruct.getTransactionValue(token.tokenType, getCelerWallet());
            BigInteger         amount = _transferFromAmount + value;

            LedgerStruct.PeerProfile[] peerProfiles = c.peerProfiles;
            LedgerStruct.PeerProfile   peerProfile  = peerProfiles[rid];
            peerProfile.deposit = peerProfile.deposit + amount;
            peerProfiles[rid]   = peerProfile;
            c.peerProfiles      = peerProfiles;
            LedgerStruct.BalanceMap balanceMap = LedgerChannel.getBalanceMapInner(c);
            LedgerStruct.setChannelMap(_channelId, c);
            DepositEvent(_channelId, balanceMap.peerAddrs, balanceMap.deposits, balanceMap.withdrawals);
            return(true);
        }