function offset(
        address user_,
        address token_
    )
        onlyActive
        public
    {
        uint256 userFromAmount = fromAmountBooks[user_] >= maxForceOffsetAmount ? maxForceOffsetAmount : fromAmountBooks[user_];
        require(block.timestamp > initCanOffsetTime);
        require(userFromAmount > 0);
        address user = getUser(user_);

        if(
            user_ == user &&
            getLoanAmount(user, token_) > 0
        ){
            emit eOffset(user, user_, userFromAmount);
            uint256 remainingXPA = executeOffset(user_, userFromAmount, token_, offsetFeeRate);
            if(remainingXPA > 0){
                require(Token(XPA).transfer(fundAccount, safeDiv(safeMul(safeSub(userFromAmount, remainingXPA), 1 ether), safeAdd(1 ether, offsetFeeRate)))); 
            } else {
                require(Token(XPA).transfer(fundAccount, safeDiv(safeMul(safeSub(userFromAmount, remainingXPA), safeSub(1 ether, offsetFeeRate)), 1 ether))); 
            }
            
            fromAmountBooks[user_] = safeSub(fromAmountBooks[user_], safeSub(userFromAmount, remainingXPA));
        }else if(
            user_ != user && 
            block.timestamp > (forceOffsetBooks[user_] + 28800) &&
            getMortgageRate(user_) >= getClosingLine()
        ){
            forceOffsetBooks[user_] = block.timestamp;
                
            uint256 punishXPA = getPunishXPA(user_); 
            emit eOffset(user, user_, punishXPA);

            uint256[3] memory forceOffsetFee;
            forceOffsetFee[0] = safeDiv(safeMul(punishXPA, forceOffsetBasicFeeRate), 1 ether); 
            forceOffsetFee[1] = safeDiv(safeMul(punishXPA, forceOffsetExtraFeeRate), 1 ether); 
            forceOffsetFee[2] = safeDiv(safeMul(punishXPA, forceOffsetExecuteFeeRate), 1 ether);
            forceOffsetFee[2] = forceOffsetFee[2] > forceOffsetExecuteMaxFee ? forceOffsetExecuteMaxFee : forceOffsetFee[2];

            profit = safeAdd(profit, forceOffsetFee[0]);
            uint256 allFee = safeAdd(forceOffsetFee[2],safeAdd(forceOffsetFee[0], forceOffsetFee[1]));
            remainingXPA = safeSub(punishXPA,allFee);

            for(uint256 i = 0; i < xpaAsset.length; i++) {
                if(getLoanAmount(user_, xpaAsset[i]) > 0){
                    remainingXPA = executeOffset(user_, remainingXPA, xpaAsset[i],0);
                    if(remainingXPA == 0){
                        break;
                    }
                }
            }
                
            fromAmountBooks[user_] = safeSub(fromAmountBooks[user_], safeSub(punishXPA, remainingXPA));
            require(Token(XPA).transfer(fundAccount, safeAdd(forceOffsetFee[1],safeSub(safeSub(punishXPA, allFee), remainingXPA)))); 
            require(Token(XPA).transfer(msg.sender, forceOffsetFee[2])); 
        }
    }