> For the complete documentation index, see [llms.txt](https://docs.quadrata.com/integration/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.quadrata.com/integration/how-to-integrate/query-attributes/via-smart-contract/query-multiple-attributes.md).

# Query multiple attributes

Use the `getAttributesBulk` function from the [QuadReader](/integration/additional-information/smart-contracts.md) 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](/integration/introduction/passport-attributes.md). | 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](/integration/introduction/passport-attributes.md) 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](/integration/how-to-integrate/query-attributes/via-smart-contract/query-helper.md)
{% 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
        }        
    }

```

####


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.quadrata.com/integration/how-to-integrate/query-attributes/via-smart-contract/query-multiple-attributes.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
