# dRamp Contract

## Contract Roles

| Role              | Description              |
| ----------------- | ------------------------ |
| Admin (onlyAdmin) | An admin of the contract |
| DevAddr (onlyDev) | The contract owner       |

## Global Parameters

| Name         | Type    | Description                                   |
| ------------ | ------- | --------------------------------------------- |
| mintFee      | uint256 | Fee charged by the dRamp for minting tokens   |
| burnFee      | uint256 | Fee charged by the dRamp for burning tokens   |
| badgeId      | uint256 | ID of any badge attached to the dRamp         |
| salePrice    | uint256 | Sale Price of a token market in the dRamp     |
| soldAccounts | uint256 | The number of token markets sold by the dRamp |
| automatic    | bool    | Automatically burn and mint tokens            |
| \_ve         | Address | The collection address attached to the dRamp  |

## Token Market Parameters

| Name       | Type                                                            | Description                                                                                                                                          |
| ---------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| status     | <p>RampStatus {<br>Pending,</p><p>Open,</p><p>Close</p><p>}</p> | Records the state of the token market                                                                                                                |
| tokenId    | uint256                                                         | The attached token ID from the collection attached to the dRamp                                                                                      |
| bountyId   | uint256                                                         | The bounty attached to the token market                                                                                                              |
| profileId  | uint256                                                         | The profile attached to the token market                                                                                                             |
| badgeId    | uint256                                                         | The badge attached to the token market                                                                                                               |
| minted     | uint256                                                         | The amount of tokens minted by the token market                                                                                                      |
| burnt      | uint256                                                         | The amount of tokens burnt by the token market                                                                                                       |
| salePrice  | uint256                                                         | The sale price of the token market. This parameter is null for token markets that are not for sale                                                   |
| maxParters | uint256                                                         | The number of partners authorized on a token market.                                                                                                 |
| cap        | uint256                                                         | A cap on the tax taken by the dRamp on minting and burning operations. This parameter is null for token markets that don't have a cap on their taxes |

## Functions

### updateAdmin - DevAddr

```typescript
   function updateAdmin(address _admin, bool _add) external onlyDev {
        isAdmin[_admin] = _add;
    }
```

The owner can add/remove other administrators to/from the contract

### createProtocol - Admin

```typescript
function createProtocol(address _token, uint _tokenId) external onlyAdmin {
    require(IRamp(helper).dTokenSetContains(_token));
    if(!AllProtocols.contains(_token)) {
        AllProtocols.add(_token);
        protocolInfo[_token].status = RampStatus.Open;
        if (_tokenId > 0) updateTokenId(_token, _tokenId);

        IRamp(helper).emitCreateProtocol(msg.sender, _token);
    }
}

function updateTokenId(address _token, uint _tokenId) public {
    require(ve(_ve).ownerOf(_tokenId) == msg.sender);
    if (AllProtocols.contains(_token)) {
        protocolInfo[_token].tokenId = _tokenId;
    }
}

function getParams() external view returns(uint,uint,uint,uint,uint,uint,bool,address) {
    return (
        badgeId,
        tokenId,
        mintFee,
        burnFee,
        salePrice,
        soldAccounts,
        automatic,
        _ve
    );
}
```

This function adds a token market on your dRamp enabling it to mint or burn that token. You can only add approved tokens. The list of approved tokens is available on the page previous to this.

You can also attach a token from the collection attached to the dRamp to enable you to regain your admin privileges in the event you lose access to your wallet but still have the token. The collection address is the \_ve parameter which is the last value returned by the getParams function

### updateProtocol - Admin

```typescript
function updateProtocol(
    address _token, 
    bool _close, 
    uint _cap,
    uint _salePrice,
    uint _maxParters
) external onlyAdmin {
    if(AllProtocols.contains(_token)) {
        uint _tokenId = protocolInfo[_token].tokenId;
        require(_tokenId == 0 || isAdmin[ve(_ve).ownerOf(_tokenId)]);
        _updateProtocol(_token, _close, _cap, _salePrice, _maxParters);
    }
}

function _updateProtocol(
    address _token, 
    bool _close, 
    uint _cap,
    uint _salePrice,
    uint _maxParters
) internal {
    if (_close) {
        protocolInfo[_token].status = RampStatus.Close;
    } else if (protocolInfo[_token].status == RampStatus.Close) {
        protocolInfo[_token].status = RampStatus.Open;
    }
    if (_cap >= IRamp(helper).minCap(_token)) {
        protocolInfo[_token].cap = _cap;    
    }
    protocolInfo[_token].salePrice = _salePrice;
    protocolInfo[_token].maxParters = _maxParters;
}
```

This function updates parameters of a token market on your dRamp. You can use the \_close parameter to close the token market.

### deleteProtocol - Admin

```typescript
function deleteProtocol(address _token) public onlyAdmin {
    require(protocolInfo[_token].minted == protocolInfo[_token].burnt);
    require(protocolInfo[_token].bountyId == 0);
    delete protocolInfo[_token];
    AllProtocols.remove(_token);
    
    IRamp(helper).emitDeleteProtocol(msg.sender, _token);
}
```

This function the market associated to the specified token. This is only possible when the token market has burnt as many of the token as it has minted and there is not bounty currently associated with it

### mint - Admin

```typescript
 function mint(address _token, address to, uint _amount, uint _identityTokenId, string memory _sessionId) external {
    checkIdentityProof(to, _identityTokenId);
    require(IAuth(contractAddress).devaddr_() == msg.sender || isAdmin[msg.sender], "R1");
    require(protocolInfo[_token].status == RampStatus.Open, "R2");
    (uint _mintable,, CollateralStatus _status) = IRamp(IContract(contractAddress).rampAds()).mintAvailable(address(this), _token);
    if (_status == CollateralStatus.OverCollateralized) {
        uint _toMint = Math.min(_mintable, _amount);
        uint _fee;
        uint _payswapFee;
        if (protocolInfo[_token].cap > 0) {
            _fee = Math.min(_toMint * mintFee / 10000, protocolInfo[_token].cap);
            _payswapFee = Math.min(_toMint * IRamp(helper).tradingFee() / 10000, protocolInfo[_token].cap);
        } else {
            _fee = _toMint * mintFee / 10000;
            _payswapFee = _toMint * IRamp(helper).tradingFee() / 10000;
        }
        totalRevenue[_token] += _fee;
        _toMint = _toMint - _fee - _payswapFee;
        protocolInfo[_token].minted += _toMint;
        IRamp(helper).mint(_token, to, _toMint, _payswapFee, _identityTokenId, _sessionId);
    }
}
```

This function enables users to mint tokens from a token market. It's only callable by the dRamp's Admin or Payswap's Admin. The

### withdraw - Admin

```typescript
function withdraw(address _token, uint amount) external onlyAdmin {
    IERC20(_token).safeTransfer(msg.sender, amount);
}
```

This withdraws available tokens from the dRamp.

### updateIndividualProtocol - Anyone

```typescript
function updateIndividualProtocol(
    address _token, 
    bool _close, 
    uint _cap,
    uint _salePrice,
    uint _maxParters
) external {
    if(AllProtocols.contains(_token)) {
        require(ve(_ve).ownerOf(protocolInfo[_token].tokenId) == msg.sender);
        require(!isAdmin[msg.sender]);
        _updateProtocol(_token, _close, _cap, _salePrice, _maxParters);
    }
}

function _updateProtocol(
    address _token, 
    bool _close, 
    uint _cap,
    uint _salePrice,
    uint _maxParters
) internal {
    if (_close) {
        protocolInfo[_token].status = RampStatus.Close;
    } else if (protocolInfo[_token].status == RampStatus.Close) {
        protocolInfo[_token].status = RampStatus.Open;
    }
    if (_cap >= IRamp(helper).minCap(_token)) {
        protocolInfo[_token].cap = _cap;    
    }
    protocolInfo[_token].salePrice = _salePrice;
    protocolInfo[_token].maxParters = _maxParters;
}
```

This function updates parameters of a token market on a dRamp but can be called by anyone who owns to associated token id. You can use the \_close parameter to close the token market.

### burn - Anyone

```typescript
function burn(address _token, uint _amount, uint _identityTokenId) external {
    checkIdentityProof(msg.sender, _identityTokenId);
    uint _toBurn = Math.min(
        _amount, 
        protocolInfo[_token].minted - protocolInfo[_token].burnt
    );
    uint _fee;
    uint _payswapFee;
    if (protocolInfo[_token].cap > 0) {
        _fee = Math.min(_toBurn * burnFee / 10000, protocolInfo[_token].cap);
        _payswapFee = Math.min(IRamp(helper).tradingFee() * _toBurn / 10000, protocolInfo[_token].cap);
    } else {
        _fee = _toBurn * burnFee / 10000;
        _payswapFee = IRamp(helper).tradingFee() * _toBurn / 10000;
    }
    _toBurn = _toBurn - _fee - _payswapFee;
    totalRevenue[_token] += _fee;
    IRamp(helper).burn(_token, msg.sender, _toBurn, _fee, _payswapFee);
    protocolInfo[_token].burnt += _toBurn;
}
```

This function enables users to burn tokens from a token market

### claimPendingRevenue - Anyone

```typescript
function claimPendingRevenue(address _token, uint _partnerBountyId) external {
    require(!isAdmin[msg.sender] && protocolPartners[_token].contains(_partnerBountyId));
    uint _toPay = IRamp(helper).claimPendingRevenue(_token, msg.sender, _partnerBountyId);
    protocolInfo[_token].minted += _toPay;
    paidRevenue[_token][_partnerBountyId] += _toPay;
    IERC20(_token).safeTransfer(msg.sender, _toPay);
}
```

This function enables token market partners to claim their pending revenue on the token market

### unlockBounty - Anyone

```typescript
function unlockBounty(address _token, uint _bountyId) external {
    require(protocolInfo[_token].minted == protocolInfo[_token].burnt);
    if(isAdmin[msg.sender]) {
        IRamp(helper).endBounty(protocolInfo[_token].bountyId);
        protocolInfo[_token].bountyId = 0;
    } else if (protocolPartners[_token].contains(_bountyId)) {
        IRamp(helper).endBounty(_bountyId);
        protocolPartners[_token].remove(_bountyId);
    }
}
```

This function deattaches a bounty from a token market

### checkIdentityProof - Anyone

```typescript
function checkIdentityProof(address _owner, uint _identityTokenId) public {
    if (collectionId > 0) {
        IMarketPlace(IContract(contractAddress).marketHelpers2())
        .checkUserIdentityProof(collectionId, _identityTokenId, _owner);
    }
}
```

This function checks that an identity token passes membership identity requirements on the associated channel/collection

### updateBounty - Anyone

```typescript
function updateBounty(address _token, uint _bountyId) external {
    IRamp(helper).checkBounty(msg.sender, _bountyId);
    require(isAdmin[msg.sender]);
    require(protocolInfo[_token].bountyId == 0);
    protocolInfo[_token].bountyId = _bountyId;
}
```

This function enables users to attach a bounty to a token market

### addPartner - Anyone

```typescript
function addPartner(address _token, uint _bountyId) external {
    address rampAds = IContract(contractAddress).rampAds();
    (,,CollateralStatus _status) = IRamp(rampAds).mintAvailable(address(this), _token);
    if (_status == CollateralStatus.UnderCollateralized ||
        protocolInfo[_token].maxParters > protocolPartners[_token].length()
    ) {
        IRamp(helper).checkBounty(msg.sender, _bountyId);
        require(!isAdmin[msg.sender]);
        require(protocolPartners[_token].length() < IContract(contractAddress).maximumSize());
        protocolPartners[_token].add(_bountyId);
        uint _share = ITrustBounty(IContract(contractAddress).trustBounty()).getBalance(_bountyId) * 10000 / IRamp(helper).getTotalBalance(address(this), _token);
        // do not account for past revenue for new partners
        paidRevenue[_token][_bountyId] += _share * totalRevenue[_token]/ 10000;
    }
}
```

This function enables users to partner with a token market and help it become overcollateralized which is necessary for it to become elligible to mint tokens

### buyAccount - Anyone

```typescript
function buyAccount(address _token, uint _tokenId, uint _bountyId) external {
    require(protocolInfo[_token].salePrice > 0);
    require(ve(_ve).ownerOf(_tokenId) == msg.sender);
    
    IERC20(ve(_ve).token()).safeTransferFrom(msg.sender, address(this), protocolInfo[_token].salePrice);
    protocolInfo[_token].salePrice = 0;
    soldAccounts += 1;
    _updateBounty(_token, _bountyId);
    updateTokenId(_token, _tokenId);
}
```

This function enables users to purchase a token market

### buyRamp - Anyone

```typescript
function buyRamp(address __ve, uint _tokenId, uint[] memory _bountyIds) external {
    require(salePrice > 0 && ve(_ve).ownerOf(_tokenId) == msg.sender);
    require(AllProtocols.length() - soldAccounts == _bountyIds.length);
    
    IERC20(ve(_ve).token()).safeTransferFrom(msg.sender, address(this), salePrice);
    for(uint i = 0; i < AllProtocols.length(); i++) {
        uint __tokenId = protocolInfo[AllProtocols.at(i)].tokenId;
        if (isAdmin[ve(_ve).ownerOf(__tokenId)]) {
            _updateBounty(AllProtocols.at(i), _bountyIds[i]);
        }
    }
    isAdmin[msg.sender] = true;
    isAdmin[devaddr_] = false;
    devaddr_ = msg.sender;
    updateDevTokenId(__ve, _tokenId);
}
```

This function enables users to purchase an entire dRamp. It requires its salePrice to be above 0 though.

### updateProfile & updateDevTokenId & updateBadgeId & updateDevFromToken - Anyone

```typescript
function updateProfile(address _token, uint _profileId) external {
  require(IProfile(IContract(contractAddress).profile()).addressToProfileId(msg.sender) == _profileId);
  require(isAdmin[msg.sender]);
  protocolInfo[_token].profileId = _profileId;
}

function updateDevTokenId(address __ve, uint _tokenId) public {
    require(ve(__ve).ownerOf(_tokenId) == msg.sender);
    require(isAdmin[msg.sender]);
    _ve = __ve;
    tokenId = _tokenId;
}

function updateBadgeId(address _token, uint _badgeId) external {
    require(ve(IRamp(helper).badgeNFT()).ownerOf(_badgeId) == msg.sender);
    require(isAdmin[msg.sender]);
    protocolInfo[_token].badgeId = _badgeId;
}

function updateDevFromToken(uint _tokenId) external {
    require(ve(_ve).ownerOf(_tokenId) == msg.sender);
    require(tokenId == _tokenId);
    isAdmin[devaddr_] = false;
    devaddr_ = msg.sender;
    isAdmin[msg.sender] = true;
}
```

If the **Owner** needs to change the ownership of the contract, they can call this function.
