# Query multiple attributes

Use the `getAttributesBulk` function from the [QuadReader](https://docs.quadrata.com/integration/additional-information/smart-contracts) smart contract to query multiple attributes about a passport holder.

### Requirements

#### Installation

Install ***@quadrata/contracts*** package

```
npm i @quadrata/contracts --save-dev
```

#### Permissions

Calling smart contract have to be granted permissions to call `getAttributesBulk` in Mainnet.\
Contact us via email at <contact@quadrata.com> or [Discord](https://discord.gg/wnJQBvwzds)

{% hint style="info" %}
Testnets like Goerli,Mumbai,etc.. do not require any permissions
{% endhint %}

### Function

{% code title="QuadReader.sol" %}

```javascript
import "@quadrata/contracts/interfaces/IQuadPassportStore.sol";

// For Solidity version >= 0.8.0.
reader.getAttributesBulk(
    address user, 
    bytes32[] calldata attributes
) external returns(
    IQuadPassportStore.Attribute[] memory attributes
);


// For Solidity version < 0.8.0.
reader.getAttributesBulkLegacy(
    address user, 
    bytes32[] calldata attributes
) external returns(
    bytes32[] attributeValues, 
    uint256[] epochs, 
    address[] issuers
);
```

{% endcode %}

#### Parameters

| Parameter  | Description                                                                                                                                    | Type                  |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| user       | address of the passport holder                                                                                                                 | address (required)    |
| attributes | The list of attributes you want to query. See: [Supported attributes](https://docs.quadrata.com/integration/introduction/passport-attributes). | bytes32\[] (required) |

#### Return values

A list of issued values for each attributes being queried.

{% hint style="warning" %}
This function will return exactly a list of the same length as the number of attributes being queried.\
If an attribute hasn't been issued yet, it's value will be: \
\
`Attribute{value: bytes32(0), epoch: uint256(0), issuer: address(0)}`
{% endhint %}

{% code title="IQuadPassportStore.sol" %}

```solidity
/// @dev Attribute store infomation as it relates to a single attribute
/// `attrKeys` Array of keys defined by (wallet address/DID + data Type)
/// `value` Attribute value
/// `epoch` timestamp when the attribute has been verified by an Issuer
/// `issuer` address of the issuer issuing the attribute
struct Attribute {
    bytes32 value;
    uint256 epoch;
    address issuer;
}
```

{% endcode %}

{% hint style="info" %}
`For Solidity version < 0.8.0`

`Use`**`getAttributesBulkLegacy()`**`which` returns three arrays. The index of each array maps to the others to create a tuple (e.g. `attributeValues[0]`, `epochs[0]`, `issuers[0]` are part of the same result).&#x20;

* **attributeValues**: Raw or hashed attribute values. See [Supported attributes](https://docs.quadrata.com/integration/introduction/passport-attributes) for the return values of each attribute.&#x20;
* **epochs:** Timestamp that indicates when the attribute was verified by the passport issuer.&#x20;
* **issuers:** Passport issuer who verified the attributes.
  {% endhint %}

### Example

{% hint style="success" %}
You can find our helper library to facilitate parsing the response => [QuadReaderUtils](https://docs.quadrata.com/integration/how-to-integrate/query-attributes/via-smart-contract/query-helper)
{% endhint %}

```solidity
import "@quadrata/contracts/interfaces/IQuadReader.sol";
import "@quadrata/contracts/interfaces/IQuadPassportStore.sol";
import "@quadrata/contracts/utility/QuadReaderUtils.sol";

contract MyDapp {
    using QuadReaderUtils for bytes32;
    
    IQuadReader public reader;
    
    function borrowMoney() external payable {
        bytes32[] memory attributesToQuery = new bytes32[](2);
        attributesToQuery[0] = keccak256("COUNTRY");
        attributesToQuery[1] = keccak256("AML");


        IQuadPassportStore.Attribute[] memory attributes = reader.getAttributesBulk(
            msg.sender, 
            attributesToQuery
        );
        
        require(attributes.length == attributesToQuery.length, "REQUIRES_COUNTRY_AND_AML");
        
        // only users residing outside the US may borrow money        
        bool isEligibleCountry = !attributes[0].value.countryIsEqual("US");
        
        // only users with AML risk score < 5 may borrow money
        bool isEligibleAML = attributes[1].value.amlLessThan(5));

        if (isEligibleCountry && isEligibleAML) {
            // Allow borrow actions
        }        
    }

```

####
