function fillDebtOffer(LTVDecisionEngineTypes.Params params)
		public returns (bytes32 agreementId)
	{
		OrderLibrary.DebtOrder memory order = params.order;
		CommitmentValues memory commitmentValues = params.creditorCommitment.values;

		bytes32 creditorCommitmentHash = hashCreditorCommitmentForOrder(commitmentValues, order);

		if (!evaluateConsent(params, creditorCommitmentHash)) {
			emit CreditorProxyError(uint8(Errors.DEBT_OFFER_NON_CONSENSUAL), order.creditor, creditorCommitmentHash);
			return NULL_ISSUANCE_HASH;
		}

		if (debtOfferFilled[creditorCommitmentHash]) {
			emit CreditorProxyError(uint8(Errors.DEBT_OFFER_ALREADY_FILLED), order.creditor, creditorCommitmentHash);
			return NULL_ISSUANCE_HASH;
		}

		if (debtOfferCancelled[creditorCommitmentHash]) {
			emit CreditorProxyError(uint8(Errors.DEBT_OFFER_CANCELLED), order.creditor, creditorCommitmentHash);
			return NULL_ISSUANCE_HASH;
		}

		if (!evaluateDecision(params)) {
			emit CreditorProxyError(
				uint8(Errors.DEBT_OFFER_CRITERIA_NOT_MET),
				order.creditor,
				creditorCommitmentHash
			);
			return NULL_ISSUANCE_HASH;
		}

		address principalToken = order.principalToken;

		
		uint tokenTransferAllowance = getAllowance(
			principalToken,
			address(this),
			contractRegistry.tokenTransferProxy()
		);

		uint totalCreditorPayment = order.principalAmount.add(order.creditorFee);

		
		if (tokenTransferAllowance < totalCreditorPayment) {
			require(setTokenTransferAllowance(principalToken, totalCreditorPayment));
		}

		
		if (totalCreditorPayment > 0) {
			require(
				transferTokensFrom(
					principalToken,
					order.creditor,
					address(this),
					totalCreditorPayment
				)
			);
		}

		agreementId = sendOrderToKernel(order);

		require(agreementId != NULL_ISSUANCE_HASH);

		debtOfferFilled[creditorCommitmentHash] = true;

		contractRegistry.debtToken().transfer(order.creditor, uint256(agreementId));

		emit DebtOfferFilled(order.creditor, creditorCommitmentHash, agreementId);

		return agreementId;
	}