Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- pragma solidity 0.4.18;
- import "./SafeMath.sol";
- import "./ERC20.sol";
- import "./TermsContract.sol";
- import "./DebtRegistry.sol";
- import "./TokenRegistry.sol";
- import "./TokenTransferProxy.sol";
- import { PermissionsLib, PermissionEvents } from "./PermissionsLib.sol";
- contract Collateralizer is Pausable, PermissionEvents {
- using PermissionsLib for PermissionsLib.Permissions;
- using SafeMath for uint;
- address public debtKernelAddress;
- DebtRegistry public debtRegistry;
- TokenRegistry public tokenRegistry;
- TokenTransferProxy public tokenTransferProxy;
- // Collateralizer here refers to the owner of the asset that is being collateralized.
- mapping(bytes32 => address) public agreementToCollateralizer;
- PermissionsLib.Permissions internal collateralizationPermissions;
- uint public constant SECONDS_IN_DAY = 24*60*60;
- string public constant CONTEXT = "collateralizer";
- event CollateralLocked(
- bytes32 indexed agreementID,
- address indexed token,
- uint amount
- );
- event CollateralReturned(
- bytes32 indexed agreementID,
- address indexed collateralizer,
- address token,
- uint amount
- );
- event CollateralSeized(
- bytes32 indexed agreementID,
- address indexed beneficiary,
- address token,
- uint amount
- );
- modifier onlyAuthorizedToCollateralize() {
- require(collateralizationPermissions.isAuthorized(msg.sender));
- _;
- }
- function Collateralizer(
- address _debtKernel,
- address _debtRegistry,
- address _tokenRegistry,
- address _tokenTransferProxy
- ) public {
- debtKernelAddress = _debtKernel;
- debtRegistry = DebtRegistry(_debtRegistry);
- tokenRegistry = TokenRegistry(_tokenRegistry);
- tokenTransferProxy = TokenTransferProxy(_tokenTransferProxy);
- }
- function collateralize(
- bytes32 agreementId,
- address collateralizer
- )
- public
- onlyAuthorizedToCollateralize
- whenNotPaused
- returns (bool _success)
- {
- // The token in which collateral is denominated
- address collateralToken;
- // The amount being put up for collateral
- uint collateralAmount;
- // The number of days a debtor has after a debt enters default
- // before their collateral is eligible for seizure.
- uint gracePeriodInDays;
- // The terms contract according to which this asset is being collateralized.
- TermsContract termsContract;
- // Fetch all relevant collateralization parameters
- (
- collateralToken,
- collateralAmount,
- gracePeriodInDays,
- termsContract
- ) = retrieveCollateralParameters(agreementId);
- require(termsContract == msg.sender);
- require(collateralAmount > 0);
- require(collateralToken != address(0));
- /*
- Ensure that the agreement has not already been collateralized.
- If the agreement has already been collateralized, this check will fail
- because any valid collateralization must have some sort of valid
- address associated with it as a collateralizer. Given that it is impossible
- to send transactions from address 0x0, this check will only fail
- when the agreement is already collateralized.
- */
- require(agreementToCollateralizer[agreementId] == address(0));
- ERC20 erc20token = ERC20(collateralToken);
- address custodian = address(this);
- /*
- The collateralizer must have sufficient balance equal to or greater
- than the amount being put up for collateral.
- */
- require(erc20token.balanceOf(collateralizer) >= collateralAmount);
- /*
- The proxy must have an allowance granted by the collateralizer equal
- to or greater than the amount being put up for collateral.
- */
- require(erc20token.allowance(collateralizer, tokenTransferProxy) >= collateralAmount);
- // store collaterallizer in mapping, effectively demarcating that the
- // agreement is now collateralized.
- agreementToCollateralizer[agreementId] = collateralizer;
- // the collateral must be successfully transferred to this contract, via a proxy.
- require(tokenTransferProxy.transferFrom(
- erc20token,
- collateralizer,
- custodian,
- collateralAmount
- ));
- // emit event that collateral has been secured.
- CollateralLocked(agreementId, collateralToken, collateralAmount);
- return true;
- }
- function returnCollateral(
- bytes32 agreementId
- )
- public
- whenNotPaused
- {
- // The token in which collateral is denominated
- address collateralToken;
- // The amount being put up for collateral
- uint collateralAmount;
- // The number of days a debtor has after a debt enters default
- // before their collateral is eligible for seizure.
- uint gracePeriodInDays;
- // The terms contract according to which this asset is being collateralized.
- TermsContract termsContract;
- // Fetch all relevant collateralization parameters.
- (
- collateralToken,
- collateralAmount,
- gracePeriodInDays,
- termsContract
- ) = retrieveCollateralParameters(agreementId);
- // Ensure a valid form of collateral is tied to this agreement id
- require(collateralAmount > 0);
- require(collateralToken != address(0));
- // Withdrawal can only occur if the collateral has yet to be withdrawn.
- // When we withdraw collateral, we reset the collateral agreement
- // in a gas-efficient manner by resetting the address of the collateralizer to 0
- require(agreementToCollateralizer[agreementId] != address(0));
- // Ensure that the debt is not in a state of default
- require(
- termsContract.getExpectedRepaymentValue(
- agreementId,
- termsContract.getTermEndTimestamp(agreementId)
- ) <= termsContract.getValueRepaidToDate(agreementId)
- );
- // determine collateralizer of the collateral.
- address collateralizer = agreementToCollateralizer[agreementId];
- // Mark agreement's collateral as withdrawn by setting the agreement's
- // collateralizer to 0x0.
- delete agreementToCollateralizer[agreementId];
- // transfer the collateral this contract was holding in escrow back to collateralizer.
- require(
- ERC20(collateralToken).transfer(
- collateralizer,
- collateralAmount
- )
- );
- // log the return event.
- CollateralReturned(
- agreementId,
- collateralizer,
- collateralToken,
- collateralAmount
- );
- }
- function seizeCollateral(
- bytes32 agreementId
- )
- public
- whenNotPaused
- {
- // The token in which collateral is denominated
- address collateralToken;
- // The amount being put up for collateral
- uint collateralAmount;
- // The number of days a debtor has after a debt enters default
- // before their collateral is eligible for seizure.
- uint gracePeriodInDays;
- // The terms contract according to which this asset is being collateralized.
- TermsContract termsContract;
- // Fetch all relevant collateralization parameters
- (
- collateralToken,
- collateralAmount,
- gracePeriodInDays,
- termsContract
- ) = retrieveCollateralParameters(agreementId);
- // Ensure a valid form of collateral is tied to this agreement id
- require(collateralAmount > 0);
- require(collateralToken != address(0));
- // Seizure can only occur if the collateral has yet to be withdrawn.
- // When we withdraw collateral, we reset the collateral agreement
- // in a gas-efficient manner by resetting the address of the collateralizer to 0
- require(agreementToCollateralizer[agreementId] != address(0));
- // Ensure debt is in a state of default when we account for the
- // specified "grace period". We do this by checking whether the
- // *current* value repaid to-date exceeds the expected repayment value
- // at the point of time at which the grace period would begin if it ended
- // now. This crucially relies on the assumption that both expected repayment value
- /// and value repaid to date monotonically increase over time
- require(
- termsContract.getExpectedRepaymentValue(
- agreementId,
- timestampAdjustedForGracePeriod(gracePeriodInDays)
- ) > termsContract.getValueRepaidToDate(agreementId)
- );
- // Mark agreement's collateral as withdrawn by setting the agreement's
- // collateralizer to 0x0.
- delete agreementToCollateralizer[agreementId];
- // determine beneficiary of the seized collateral.
- address beneficiary = debtRegistry.getBeneficiary(agreementId);
- // transfer the collateral this contract was holding in escrow to beneficiary.
- require(
- ERC20(collateralToken).transfer(
- beneficiary,
- collateralAmount
- )
- );
- // log the seizure event.
- CollateralSeized(
- agreementId,
- beneficiary,
- collateralToken,
- collateralAmount
- );
- }
- function addAuthorizedCollateralizeAgent(address agent)
- public
- onlyOwner
- {
- collateralizationPermissions.authorize(agent, CONTEXT);
- }
- function revokeCollateralizeAuthorization(address agent)
- public
- onlyOwner
- {
- collateralizationPermissions.revokeAuthorization(agent, CONTEXT);
- }
- function getAuthorizedCollateralizeAgents()
- public
- view
- returns(address[])
- {
- return collateralizationPermissions.getAuthorizedAgents();
- }
- function unpackCollateralParametersFromBytes(bytes32 parameters)
- public
- pure
- returns (uint, uint, uint)
- {
- // The first byte of the 108 reserved bits represents the collateral token.
- bytes32 collateralTokenIndexShifted =
- parameters & 0x0000000000000000000000000000000000000ff0000000000000000000000000;
- // The subsequent 92 bits represents the collateral amount, as denominated in the above token.
- bytes32 collateralAmountShifted =
- parameters & 0x000000000000000000000000000000000000000fffffffffffffffffffffff00;
- // We bit-shift these values, respectively, 100 bits and 8 bits right using
- // mathematical operations, so that their 32 byte integer counterparts
- // correspond to the intended values packed in the 32 byte string
- uint collateralTokenIndex = uint(collateralTokenIndexShifted) / 2 ** 100;
- uint collateralAmount = uint(collateralAmountShifted) / 2 ** 8;
- // The last byte of the parameters represents the "grace period" of the loan,
- // as defined in terms of days.
- // Since this value takes the rightmost place in the parameters string,
- // we do not need to bit-shift it.
- bytes32 gracePeriodInDays =
- parameters & 0x00000000000000000000000000000000000000000000000000000000000000ff;
- return (
- collateralTokenIndex,
- collateralAmount,
- uint(gracePeriodInDays)
- );
- }
- function timestampAdjustedForGracePeriod(uint gracePeriodInDays)
- public
- view
- returns (uint)
- {
- return block.timestamp.sub(
- SECONDS_IN_DAY.mul(gracePeriodInDays)
- );
- }
- function retrieveCollateralParameters(bytes32 agreementId)
- internal
- view
- returns (
- address _collateralToken,
- uint _collateralAmount,
- uint _gracePeriodInDays,
- TermsContract _termsContract
- )
- {
- address termsContractAddress;
- bytes32 termsContractParameters;
- // Pull the terms contract and associated parameters for the agreement
- (termsContractAddress, termsContractParameters) = debtRegistry.getTerms(agreementId);
- uint collateralTokenIndex;
- uint collateralAmount;
- uint gracePeriodInDays;
- // Unpack terms contract parameters in order to get collateralization-specific params
- (
- collateralTokenIndex,
- collateralAmount,
- gracePeriodInDays
- ) = unpackCollateralParametersFromBytes(termsContractParameters);
- // Resolve address of token associated with this agreement in token registry
- address collateralTokenAddress = tokenRegistry.getTokenAddressByIndex(collateralTokenIndex);
- return (
- collateralTokenAddress,
- collateralAmount,
- gracePeriodInDays,
- TermsContract(termsContractAddress)
- );
- }
- }
Add Comment
Please, Sign In to add comment