# Implementation

## State Variables

* `bool public isTransferable`\
  Determines whether token transfers (beyond minting) are allowed.
* `bool public isOutsideTransferAllowed`\
  If `true`, tokens may be transferred to any address. If `false`, tokens can only be transferred to addresses that already hold tokens.
* `uint256 public materialContributionWeight`\
  The multiplier applied to the `materialContribution` when minting new tokens.
* `uint256 private adminCount`\
  Tracks the number of current admins to prevent removing the last admin.
* `mapping(address => bool) private hasReceivedTokens`\
  Tracks if an address has ever received tokens (either via mint or transfer).
* `mapping(address => uint256) private firstMintTime`\
  Records the block timestamp of the first time an address received tokens.

## Functions

### Constructor

```solidity
constructor(
    address initialOwner,
    bool _isTransferable,
    bool _isOutsideTransferAllowed,
    uint256 _materialWeight,
    string memory name,
    string memory symbol
) ERC20(name, symbol)
```

* **Parameters**:
  * `initialOwner`: Address to receive the `ADMIN_ROLE`.
    * `_isTransferable`: Initial setting for enabling or disabling transfers.
    * `_isOutsideTransferAllowed`: Initial setting for allowing or disallowing transfers to addresses that do not yet hold tokens.
    * `_materialWeight`: Initial multiplier for material contributions.
    * `name`: ERC20 token name.
    * `symbol`: ERC20 token symbol.

### Mint

```solidity
function mint(
        address to,
        uint256 materialContribution,
        uint256 timeContribution
    ) external onlyRole(ADMIN_ROLE) 
```

Mints new tokens to a specified address.\
Calculation:

```solidity
uint256 timeWeight = getTimeWeight(to);
uint256 totalAmount = ((materialContribution * materialContributionWeight)) / 1000
                    + ((timeContribution * timeWeight) / 1000);
_mint(to, totalAmount);
```

* If `firstMintTime[to]` is `0`, it is set to the current block timestamp.
* Requires `ADMIN_ROLE`.

### Batch Mint

```solidity
function batchMint(
        address[] calldata recipients,
        uint256[] calldata materialContributions,
        uint256[] calldata timeContributions
    ) external onlyRole(ADMIN_ROLE)
```

Mints new tokens to all the specified addresses, calculating the material and time contribution for each recipient.&#x20;

### Update Settings

```solidity
function updateSettings(
        bool _isTransferable,
        bool _isOutsideTransferAllowed,
        uint256 _materialWeight
    ) external onlyRole(ADMIN_ROLE)
```

Updates the settings used for the calculations of the team points amount in the mint function.&#x20;

### Add Admin

```solidity
function addAdmin(address newAdmin) external onlyRole(ADMIN_ROLE)
```

Adds a new admin. Can be called only by other admins. It is mandatory for the new admin to already be a token holder, otherwise it will fail.&#x20;

### Remove Admin

```solidity
function removeAdmin(address toRemove) external onlyRole(ADMIN_ROLE)
```

Removes an admin. Can be called only by other admins. It ensures that the admin being removed is not the only admin in the organization, so the organization won't be locked.&#x20;

### Check Is Admin

```solidity
function isAdmin(address account) public view returns (bool)
```

Public view function that can be called by anyone, returns true if the address passed as parameter is an admin in the organization.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://collabberry.gitbook.io/collabberry-docs/technical/images-and-media/team-points/implementation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
