public static object resolvePaymentByConditions(byte[] resolvePayRequestBs)
        {
            PbChain.ResolvePayByConditionsRequest resolvePayRequest = new PbChain.ResolvePayByConditionsRequest();
            resolvePayRequest = (PbChain.ResolvePayByConditionsRequest)Helper.Deserialize(resolvePayRequestBs);
            PbEntity.ConditionalPay   pay      = Helper.Deserialize(resolvePayRequest.condPay) as PbEntity.ConditionalPay;
            PbEntity.TransferFunction function = pay.transferFunc;
            byte       funcType = function.logicType;
            BigInteger amount   = 0;

            PbEntity.TransferFunctionType TransferFunctionType = PbEntity.getTransferFunctionType();
            if (funcType == TransferFunctionType.BOOLEAN_AND)
            {
                amount = _calculateBooleanAndPayment(pay, resolvePayRequest.hashPreimages);
            }
            else if (funcType == TransferFunctionType.BOOLEAN_OR)
            {
                amount = _calculateBooleanOrPayment(pay, resolvePayRequest.hashPreimages);
            }
            else if (_isNumericLogic(funcType))
            {
                amount = _calculateNumericLogicPayment(pay, resolvePayRequest.hashPreimages, funcType);
            }
            else
            {
                BasicMethods.assert(false, "error");
            }
            byte[] payHash = SmartContract.Sha256(resolvePayRequest.condPay);
            _resolvePayment(pay, payHash, amount);
            return(true);
        }
        public static void _resolvePayment(PbEntity.ConditionalPay _pay, byte[] _payHash, BigInteger _amount)
        {
            BasicMethods.assert(_amount >= 0, "amount is less than zero");

            BigInteger now = Blockchain.GetHeight();

            BasicMethods.assert(now <= _pay.resolveDeadline, "passed pay resolve deadline in condPay msg");

            byte[] payId = _calculatePayId(_payHash, ExecutionEngine.ExecutingScriptHash);

            byte[] payRegistryHash      = getPayRegistryHash();
            DynamicCallContract dyncall = (DynamicCallContract)payRegistryHash.ToDelegate();

            BigInteger[] res             = (BigInteger[])dyncall("getPayInfo", new object[] { payId });
            BigInteger   currentAmt      = res[0];
            BigInteger   currentDeadline = res[1];

            BasicMethods.assert(
                currentDeadline == 0 || now <= currentDeadline,
                "Passed onchain resolve pay deadline"
                );
            PbEntity.TransferFunction transferFunction = _pay.transferFunc;
            PbEntity.TokenTransfer    tokenTransfer    = transferFunction.maxTransfer;
            PbEntity.AccountAmtPair   accountAmtPair   = tokenTransfer.receiver;
            if (currentDeadline > 0)
            {
                BasicMethods.assert(_amount > currentAmt, "New amount is not larger");

                if (_amount == accountAmtPair.amt)
                {
                    BasicMethods.assert((bool)dyncall("setPayInfo", new object[] { _payHash, _amount, now }), "setPayInfo error");
                    ResolvePayment(payId, _amount, now);
                }
                else
                {
                    BasicMethods.assert((bool)dyncall("setPayAmount", new object[] { _payHash, _amount }), "setPayAmount error");
                    ResolvePayment(payId, _amount, currentDeadline);
                }
            }
            else
            {
                BigInteger newDeadline = 0;
                if (_amount == accountAmtPair.amt)
                {
                    newDeadline = now;
                }
                else
                {
                    newDeadline = min(now + _pay.resolveTimeout, _pay.resolveDeadline);
                    BasicMethods.assert(newDeadline > 0, "new resolve deadline is not greater than 0");
                }

                BasicMethods.assert((bool)dyncall("setPayInfo", new object[] { _payHash, _amount, newDeadline }), "setPayInfo error");
                ResolvePayment(payId, _amount, currentDeadline);
            }
        }
        private static BigInteger _calculateBooleanOrPayment(PbEntity.ConditionalPay _pay, byte[][] _preimages)
        {
            int  j = 0;
            bool hasContractCond     = false;
            bool hasTrueContractCond = false;

            PbEntity.ConditionType ConditionType = PbEntity.getConditionType();
            PbEntity.Condition[]   conditions    = _pay.conditions;
            for (var i = 0; i < conditions.Length; i++)
            {
                PbEntity.Condition cond = _pay.conditions[i];
                if (cond.conditionType == ConditionType.HASH_LOCK)
                {
                    BasicMethods.assert(SmartContract.Sha256(_preimages[j]) == cond.hashLock, "wrong preimage");
                    j++;
                }
                else if (
                    cond.conditionType == ConditionType.DEPLOYED_CONTRACT ||
                    cond.conditionType == ConditionType.VIRTUAL_CONTRACT
                    )
                {
                    byte[] booleanCondHash      = _getCondAddress(cond);
                    DynamicCallContract dyncall = (DynamicCallContract)booleanCondHash.ToDelegate();
                    BasicMethods.assert((bool)dyncall("isFinalized", new object[] { cond.argsQueryFinalization }), "Condition is not finalized");
                    hasContractCond = true;

                    bool outcome = (bool)dyncall("getOutcome", new object[] { cond.argsQueryOutcome });
                    if (outcome)
                    {
                        hasTrueContractCond = true;
                    }
                }
                else
                {
                    BasicMethods.assert(false, "condition type error");
                }
            }
            if (!hasContractCond || hasTrueContractCond)
            {
                PbEntity.TransferFunction transferFunction = _pay.transferFunc;
                PbEntity.TokenTransfer    tokenTransfer    = transferFunction.maxTransfer;
                PbEntity.AccountAmtPair   accountAmtPair   = tokenTransfer.receiver;
                return(accountAmtPair.amt);
            }
            else
            {
                return(0);
            }
        }
        public static object resolvePaymentByVouchedResult(byte[] vouchedPayResultBs)
        {
            PbEntity.VouchedCondPayResult vouchedPayResult = new PbEntity.VouchedCondPayResult();
            vouchedPayResult = (PbEntity.VouchedCondPayResult)Helper.Deserialize(vouchedPayResultBs);
            PbEntity.CondPayResult  payResult = (PbEntity.CondPayResult)Helper.Deserialize(vouchedPayResult.condPayResult);
            PbEntity.ConditionalPay pay       = (PbEntity.ConditionalPay)Helper.Deserialize(payResult.condPay);

            PbEntity.TransferFunction transaferFunction = pay.transferFunc;
            PbEntity.TokenTransfer    tokenTransfer     = transaferFunction.maxTransfer;
            PbEntity.AccountAmtPair   accountAmtPair    = tokenTransfer.receiver;
            BasicMethods.assert(payResult.amount <= accountAmtPair.amt, "exceed max transfer amount");
            byte[] hash            = SmartContract.Sha256(vouchedPayResult.condPayResult);
            bool   srcVerifiedRes  = SmartContract.VerifySignature(hash, vouchedPayResult.sigOfSrc, pay.src);
            bool   destVerifiedRes = SmartContract.VerifySignature(hash, vouchedPayResult.sigOfDest, pay.dest);

            BasicMethods.assert(srcVerifiedRes && destVerifiedRes, "verify signature failed");

            byte[] payHash = SmartContract.Sha256(payResult.condPay);

            _resolvePayment(pay, payHash, payResult.amount);

            return(true);
        }
        private static BigInteger _calculateNumericLogicPayment(PbEntity.ConditionalPay _pay, byte[][] _preimages, byte _funcType)
        {
            int        j              = 0;
            BigInteger amount         = 0;
            bool       hasContracCond = false;

            PbEntity.ConditionType        ConditionType        = PbEntity.getConditionType();
            PbEntity.TransferFunctionType TransferFunctionType = PbEntity.getTransferFunctionType();
            PbEntity.Condition[]          conditions           = _pay.conditions;
            for (var i = 0; i < conditions.Length; i++)
            {
                PbEntity.Condition cond = _pay.conditions[i];
                if (cond.conditionType == ConditionType.HASH_LOCK)
                {
                    BasicMethods.assert(SmartContract.Sha256(_preimages[j]) == cond.hashLock, "wrong preimage");
                    j++;
                }
                else if (
                    cond.conditionType == ConditionType.DEPLOYED_CONTRACT ||
                    cond.conditionType == ConditionType.VIRTUAL_CONTRACT
                    )
                {
                    byte[] numericCondHash      = _getCondAddress(cond);
                    DynamicCallContract dyncall = (DynamicCallContract)numericCondHash.ToDelegate();
                    BasicMethods.assert((bool)dyncall("isFinalized", new object[] { cond.argsQueryFinalization }), "Condition is not finalized");

                    BigInteger outcome = (BigInteger)dyncall("getOutcome", new object[] { cond.argsQueryOutcome });

                    if (_funcType == TransferFunctionType.NUMERIC_ADD)
                    {
                        amount = amount + outcome;
                    }
                    else if (_funcType == TransferFunctionType.NUMERIC_MAX)
                    {
                        amount = max(amount, outcome);
                    }
                    else if (_funcType == TransferFunctionType.NUMERIC_MIN)
                    {
                        if (hasContracCond)
                        {
                            amount = min(amount, outcome);
                        }
                        else
                        {
                            amount = outcome;
                        }
                    }
                    else
                    {
                        BasicMethods.assert(false, "error");
                    }
                    hasContracCond = true;
                }
                else
                {
                    BasicMethods.assert(false, "condition type error");
                }
            }
            PbEntity.TransferFunction transferFunction = _pay.transferFunc;
            PbEntity.TokenTransfer    tokenTransfer    = transferFunction.maxTransfer;
            PbEntity.AccountAmtPair   accountAmtPair   = tokenTransfer.receiver;
            if (hasContracCond)
            {
                BasicMethods.assert(amount <= accountAmtPair.amt, "exceed max transfer amount");
                return(amount);
            }
            else
            {
                return(accountAmtPair.amt);
            }
        }