NAV
JS

Getting Started

Introduction

Welcome to Spectral, the leading provider of on-chain risk insight! This developer documentation will touch on our available forms of delivery, our products, and how to get started today!

If you have any questions regarding any of our products, get in touch with us!

Version: 0.1.0

Integrations Overview

There are three methods to integrate Spectral's risk insights into your application.

Scoracle Contract

The Scoracle Contract is a Solidity smart contract (the on-chain Chainlink oracle contract) that pulls the MACRO score from Spectral's Chainlink node.

Scoracle Contract Quickstart

To start the development with Spectral's Scoracle Contract:

  1. Follow the Prerequisites To Interacting With The Scoracle Contract section.
  2. Check out the Scoracle Example GitHub project. You can use it as a skeleton for your app.

Prerequisites To Interacting With The Scoracle Contract

To request a score from the Scoracle Contract:

  1. Arbitrum Goerli Test network must be available in your crypto wallet, such as Metamask. To add Arbitrum Goerli Test network to your wallet, visit Arbitrum Goerli Explorer, scroll to the bottom of the page, and click on Add Arbitrum One Testnet Network on the right side of the footer.
  2. Bridge testnet ETH and LINK from Goerli to Arbitrum Goerli using Arbitrum's Bridge.
  3. You must have access to the Arbitrum Goerli RPC endpoint on Alchemy or Infura.

To see a practical example, check Scoracle Example GitHub project.

Scoracle Contract Variables

Scoracle Contract Address

Contract Name Network ChainID Address
Scoracle.sol Arbitrum Goerli 421613 0xe953f329041dA0D5Cf23159abc4b45f6fbf8Ab17

Score Type ID

Score Type ID (Chainlink's externalJobID)
9348f5ba3f574f65958a675e468da9c8

Scoracle.sol - Integration

To integrate the MACRO score into your smart contract using Spectral's Scoracle Contract:

  1. Create IScoracle interface.
  2. Import the IScoracle interface and use it in your project.
  3. Obtain user signature.
  4. Prepare Score Type Job ID.
  5. Interact with your smart contract.

Scoracle.sol - Create IScoracle Interface

./contracts/interfaces/IScoracle.sol
pragma solidity 0.8.11;

interface IScoracle {
    struct ScoreData {
        uint40 lastUpdated;
        uint216 score;
        bytes extraData;
    }

    //===============Events===============

    /**
     * @dev emitted upon callback function of chainlink call. emits the address that was updated, the time it was updatedand the tick that was returned
     * @param addressToScore The address whose score is being updated
     * @param lastUpdated Timestamp of last update
     * @param score The new score
     * @param extraData Extra data to the type of score request
     **/
    event ScoreUpdated(address indexed addressToScore, uint256 lastUpdated, uint256 score, bytes extraData);

    /**
     * @dev Added a new score type
     * @param scoreTypeJobId The new adapter job id
     * @param scoreTypeName The new score type name
     **/
    event ScoreTypeAdded(bytes32 indexed scoreTypeJobId, string scoreTypeName);

    /**
     * @dev Deactivated a score type
     * @param scoreTypeJobId The new adapter job id
     **/
    event ScoreTypeDeactivated(bytes32 indexed scoreTypeJobId);

    /**
     * @dev Updated the chainlink node address
     * @param chainlinkNode The new chainlink node address
     **/
    event ChainlinkNodeUpdated(address indexed chainlinkNode);

    /**
     * @dev Updated the chainlink oracle address
     * @param chainlinkOracle The new chainlink oracle address
     **/
    event ChainlinkOracleUpdated(address indexed chainlinkOracle);

    /**
     * @dev Updated the base fee
     * @param baseFee Base fee updated
     **/
    event BaseFeeUpdated(uint256 baseFee);

    /**
     * @dev Updated the chainlink fee
     * @param chainlinkFee The new chainlink fee
     **/
    event ChainlinkFeeUpdated(uint256 chainlinkFee);

    //===============Main Functions===============

    function scoreRequest(
        address addressToScore,
        bytes32 _scoreTypeJobId,
        bytes memory _userSignature
    ) external payable;

    //===============Governance/Admin Functions===============

    function addScoreType(bytes32 _scoreTypeJobId, string memory _scoreTypeName) external;

    function deactivateScoreType(bytes32 _scoreTypeJobId) external;

    function updateChainlinkNode(address chainlinkNode) external;

    function updateChainlinkOracle(address chainlinkOracle) external;

    function updateBaseFee(uint256 baseFee) external;

    function updateChainlinkFee(uint256 chainlinkFee) external;

    function depositLINK(uint256 amount) external;

    function withdrawLINK(uint256 amount) external;

    function withdrawETH(uint256 amount) external;

    //===============Get Functions===============

    function getScore(address _user, bytes32 _scoreTypeJobId) external view returns (ScoreData memory scoreData);

    function checkScoreTypeExists(bytes32 _scoreTypeJobId)
        external
        view
        returns (
            bool,
            string memory,
            bytes32
        );

    function getChainlinkNode() external view returns (address);

    function getChainlinkOracle() external view returns (address);

    function getBaseFee() external view returns (uint256);

    function getChainlinkFee() external view returns (uint256);

    function getScoreBounds() external view returns (uint256, uint256);
}

Create a file called IScoracle.sol in the contracts/interfaces folder of your repository. Copy and paste the following code into the IScoracle.sol file.

Scoracle.sol - Import The IScoracle Interface

./contracts/MyContract.sol
pragma solidity 0.8.11;

import "./interfaces/IScoracle.sol";

contract MyContract {

    // The Deployed Scoracle.sol contract address on Arbitrum Goerli
    address constant SCORACLE_ADDRESS = 0xe953f329041dA0D5Cf23159abc4b45f6fbf8Ab17;

    constructor() {}

    // calcualateMacroScore - The function will (re)calculate a user's score by making a score request to the Scoracle contract
    // The Scoracle contract will then make request to the Chainlink Node where the score request will be fulfilled.
    function calculateMacroScore(
        bytes32 _scoreTypeJobId,
        bytes memory _userSignature
    ) external {
        IScoracle scoracle = IScoracle(SCORACLE_ADDRESS);
        scoracle.scoreRequest(msg.sender, _scoreTypeJobId, _userSignature);
    }

    // prequalifyUser - The function reads the user's score from the Scoracl contract's state and will prequalify the user for X depending on their score.
    function prequalifyUser(
        bytes32 _scoreTypeJobId
    ) public view returns (bool prequalified, uint256 score) {

        IScoracle scoracle = IScoracle(SCORACLE_ADDRESS);

        // Scoracle's getScore will read an already calculated score from the Scoracle contract's state.
        IScoracle.ScoreData memory scoreData = scoracle.getScore(msg.sender, _scoreTypeJobId);

        prequalified = (scoreData.score > 650) ? true : false;

        return (prequalified, scoreData.score);
    }
}

Import the IScoracle.sol interface into your smart contract. Then, create an instance of the Scoracle Contract using the IScoracle interface and deployed Scoracle Contract address.

With an instance of the Scoracle Contract in your code, you can now call the external functions in the Scoracle Contract to request a MACRO score for a particular address.

Scoracle.sol - Obtain User Signature

./helpers/utils.ts
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import * as ethers from 'ethers';

export const signScoracleMessage = (
  account: SignerWithAddress,
  scoracleAddress: string,
  chainId: number,
  nonce: number
) => {
  return account.signMessage(
    ethers.utils.arrayify(
      ethers.utils.solidityKeccak256(
        ['address', 'address', 'uint256', 'uint256'],
        [account.address, scoracleAddress, chainId, nonce]
      )
    )
  );
};

To request the Scoracle Contract to calculate MACRO score (scoreRequest() function), the user will first need to sign the message to obtain their signature.

Create a file ./helpers/utils.ts with the following content.

Scoracle.sol - Prepare Score Type Job ID

./helpers/utils.ts
import * as ethers from 'ethers';

export const signScoracleMessage = (
  (...)
)

// https://github.com/ethers-io/ethers.js/issues/66#issuecomment-370121220
export const stringToBytes32 = (text: string) => {
  let data = ethers.utils.toUtf8Bytes(text);
  if (data.length > 32) {
    throw new Error('too long');
  }
  data = ethers.utils.zeroPad(data, 32);
  return ethers.utils.hexlify(data);
};

You will need to submit the Score Type Job ID (_scoreTypeJobId parameter) to scoreRequest() function. Score Type Job ID must be converted from string to bytes32.

Add the following content to ./helpers/utils.ts.

Scoracle.sol - Interact With MyContract.sol

const SCORE_TYPE_ID = '9348f5ba3f574f65958a675e468da9c8';
const DeFiScoreIdType = stringToBytes32(SCORE_TYPE_ID);
const dummy_address = "0x000000000000000000000000000000000000dEaD";
const SCORACLE_ADDRESS = "0xe953f329041dA0D5Cf23159abc4b45f6fbf8Ab17";
const CHAIN_ID = 421613;
// Remember that the Scoracle.sol contract keeps track of used nonces for each user!
// After every request, the nonce must be incremented. 
let nonce = 0;
const accountSignature = await signScoracleMessage(dummy_address, SCORACLE_ADDRESS, CHAIN_ID, nonce);

// make request
await myContract.connect(accounts[0]).calculateMacroScore(DeFiScoreIdType, accountSignature);

Once you have all the helper functions created, you can use them to generate the arguments required to interact with the contract functions in MyContract.sol.

Remember that the Scoracle.sol contract keeps track of used nonces for each user. So you will need to manage nonces when making requests. After every request, the nonce must be incremented.

REST API

The Spectral REST API is a bridge for partners to pull risk insights directly into their application.

REST API Quickstart

To start the development with Spectral's REST API:

  1. Visit Spectral's Partner Dashboard to generate an API Key.
  2. Use generated API Key to authenticate API requests as described in the Authentication section.
  3. Trigger MACRO score calculation for a wallet address as described in the Calculate MACRO Score section.
  4. Read the calculated MACRO score with additional data as described in the Get MACRO Score section.

Spectral's URLs

Spectral's URL is the base URL for making API requests to the REST API for pulling data directly into your applications.

REST API URL

https://api.spectral.finance

REST API Authentication

Sample HTTP Request

GET /api/v1/addresses/0x573d19B66Cdc33f7E751f2a478ECeCe95155e798
Host: https://api.spectral.finance
Authorization: Bearer SFMYYYY.g2kfhsjAACRjNjliZWIwZS1jYTc1LTRjODUtOWVlMy01YThiZmI0MTAxNTVuBgCAlkjahsdlkfAFiAAFRgA.iEtc7xPGEemU-Z63sDQSTNmVFzCogdPycG7sAUK7p9k...

All requests to the REST API have to be authenticated with an API key (bearer access token). To get an API Key, visit Spectral's Partner Dashboard.!

Include the token in the HTTP Authorization header of your REST requests as a bearer token:

Authorization: Bearer <token>

REST API Endpoints

Calculate MACRO Score

   curl -i -X POST \
   'https://api.spectral.finance/api/v1/addresses/{wallet_address}/calculate_score'

Description: Initiates calculation of a wallet holder's score.

HTTP Request

POST /api/v1/addresses/{wallet_address}/calculate_score

Parameters

Name Located in Description Required Type
wallet_address path Wallet Address Yes string

Responses

Code Description
200 MACRO score calculation has been successfully scheduled.

Get MACRO Score

   curl -i -X GET \
   'https://api.spectral.finance/api/v1/addresses/{wallet_address}'

Sample response

   {
    "score": "350.00",
    "score_ingredients": {
      "credit_mix": 2,
      "defi_actions": 3,
      "health_and_risk": 4,
      "liquidation": 5,
      "market": 1,
      "time": 6,
      "wallet": 7
    },
    "score_timestamp": "2019-08-24T14:15:22Z",
    "probability_of_liquidation": "72.52",
    "risk_level": "HIGH_RISK",
    "wallet_address": "0xb4537b5bDfF24F757b939E27510b107BE2Ad473C"
   }

Description: Requests the pre-calculated MACRO score of a given wallet holder. If score_timestamp isn't up-to-date, the response might not be the most accurate. Specifically, the risk_level or probability_of_liquidation may be null. To get updated values, initiate the score calculation.

HTTP Request

GET /api/v1/addresses/{wallet_address}

Parameters

Name Located in Description Required Type
wallet_address path Wallet Address Yes string

Responses

Code Description
200 Wallet Details

List Wallets

   curl -i -X GET \
   'https://api.spectral.finance/api/v1/addresses'

Sample response

   [{
      "score": "350.00",
      "score_ingredients": {
        "credit_mix": 2,
        "defi_actions": 3,
        "health_and_risk": 4,
        "liquidation": 5,
        "market": 1,
        "time": 6,
        "wallet": 7
      },
      "score_timestamp": "2019-08-24T14:15:22Z",
      "probability_of_liquidation": "72.52",
      "risk_level": "HIGH_RISK",
      "wallet_address": "0xb4537b5bDfF24F757b939E27510b107BE2Ad473C"
    },
    {
      "score": "740.00",
      "score_ingredients": {
        "credit_mix": 2,
        "defi_actions": 6,
        "health_and_risk": 4,
        "liquidation": 5,
        "market": 1,
        "time": 3,
        "wallet": 7
      },
      "score_timestamp": "2019-08-24T14:11:22Z",
      "probability_of_liquidation": "39.42",
      "risk_level": "VERY_LOW_RISK",
      "wallet_address": "0xD7A556117f38c352a466F3DF33229a0ff8C4FC66"
   }]

Description: Requests information about all the wallets associated with the integration. Please note that only addresses that were associated using SDK integration are returned.

HTTP Request

GET /api/v1/addresses

Responses

Code Description
200 Returns an array of Wallet Details

REST API Objects

Wallet Details

Attribute Type Format Description
score string Number MACRO score value.
score_ingredients object Score Ingredients Additional ingredients of the MACRO score.
score_timestamp string Date Time Timestamp at which the score has been calculated.
probability_of_liquidation string Number Probability of liquidation.
risk_level string Describes the level of risk associated with the wallet. Possible values are: VERY_HIGH_RISK, HIGH_RISK, MEDIUM_RISK, LOW_RISK, VERY_LOW_RISK.
wallet_address string Ethereum wallet address

Score Ingredients

Each score ingredient is valued from [1-7], representing its effect on a user's score - with 1 having the highest negative impact and 7 the most positively supporting the score. A score ingredient of 0 means the user doesn't have enough activities.

Attribute Type Format Description
credit_mix integer Consideration of the number of DeFi lending protocols interacted with to assess the protocol concentration risk.
defi_actions integer Assessment of the various transactions undertaken on the DeFi lending protocols, e.g. borrowing, repayments, deposits, etc.
health_and_risk integer Evaluation of the amount of headroom maintained as part of your borrowing activities, similar to LTV.
liquidation integer Consideration of any historical liquidation events triggered on any of the bundled wallets.
market integer Evaluation of the general market volatility at the time of one's on-chain activities.
time integer Analysis of various time-based factors, e.g. length of wallet history.
wallet integer Assessment of the trend of wallet balance, transactions, and its composition.

SDK

Overview

The Spectral SDK provides additional integration of Spectral MACRO score into React applications. The SDK communicates with Spectral's APIs to retrieve information on risk insights.

After integrating with the SDK, you will get additional insights about users that computed Spectral's MACRO score using your application.

DEMO PAGE

Spectral Modal Video

Prerequisites

Partner ID

Access to the SDK requires a Partner ID. To get a Partner ID, visit Spectral's Partner Dashboard.

SDK Installation

In order to install the SDK run

npm install @spectral-finance/spectral-modal

or

yarn add @spectral-finance/spectral-modal

SpectralProvider Usage

import { SpectralProvider } from "@spectral-finance/spectral-modal";

export const App = () => {
  return (
    <SpectralProvider logo="yourLogoImageURL" partnerId="yourPartnerId">
        // Your App or Router Component
        {...}
    </SpectralProvider>
  );
};
  1. Import SpectralProvider and wrap it around the root app component.
  2. Use the logo parameter to apply a custom logo.
  3. Use the partnerID parameter to verify your Partner ID.

Calculate MACRO Score From Within Your Application

import { SpectralProvider } from "@spectral-finance/spectral-modal";

export const Home = () => {
  const { start, score } = useSpectral();
  const [myScore, setMyScore] = useState();

  useEffect(() => {
    if (!score) {
      console.log("Score not calculated");
      return;
    }
    console.log(`Hooray! your score is ${score}`);
    setMyScore(score);
  }, [score]);

  return (
    <div>
      {/* Opens the Spectral Modal and starts the bundle and
          calculation process */}
      <button type="button" onClick={start}>
        Calculate Spectral Score
      </button>
    </div>
  );
};

The useSpectral hook can be used anywhere inside the app context. Once the MACRO score is calculated it will be served within the score key provided by the hook.

JS