@parifi/sdk
Version:
Parifi SDK with common utility functions
323 lines (321 loc) • 10.1 kB
JavaScript
// src/distribution/index.ts
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
import { encodeFunctionData } from "viem";
// src/common/constants.ts
import { Decimal } from "decimal.js";
var PRECISION_MULTIPLIER = new Decimal("10000");
var DEVIATION_PRECISION_MULTIPLIER = new Decimal(10).pow(12);
var SECONDS_IN_A_YEAR = new Decimal(365 * 24 * 60 * 60);
var MAX_FEE = new Decimal(1e7);
var WAD = new Decimal(10).pow(18);
var DECIMAL_10 = new Decimal(10);
var DECIMAL_ZERO = new Decimal(0);
var BIGINT_ZERO = BigInt(0);
var ONE_GWEI = 1e9;
var DEFAULT_GAS_PRICE = 2 * ONE_GWEI;
var REWARD_DISTRIBUTOR_ADDRESSES = {
[8453 /* BASE */]: {
esprf: "0x6511718804180CC57833fEA036389A24604Dfc69",
prf: "0x0000000000000000000000000000000000000000",
rt: "0x648d6D711860699A11aBa192E9daBAfb6408af18"
}
};
var REWARD_DISTRIBUTOR_ABI = [
{
inputs: [{ internalType: "contract IERC20", name: "_rewardToken", type: "address" }],
stateMutability: "nonpayable",
type: "constructor"
},
{ inputs: [], name: "AccessControlBadConfirmation", type: "error" },
{
inputs: [
{ internalType: "address", name: "account", type: "address" },
{ internalType: "bytes32", name: "neededRole", type: "bytes32" }
],
name: "AccessControlUnauthorizedAccount",
type: "error"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "address", name: "user", type: "address" },
{ indexed: false, internalType: "uint256", name: "amount", type: "uint256" }
],
name: "RewardClaimed",
type: "event"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "bytes32", name: "role", type: "bytes32" },
{ indexed: true, internalType: "bytes32", name: "previousAdminRole", type: "bytes32" },
{ indexed: true, internalType: "bytes32", name: "newAdminRole", type: "bytes32" }
],
name: "RoleAdminChanged",
type: "event"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "bytes32", name: "role", type: "bytes32" },
{ indexed: true, internalType: "address", name: "account", type: "address" },
{ indexed: true, internalType: "address", name: "sender", type: "address" }
],
name: "RoleGranted",
type: "event"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "bytes32", name: "role", type: "bytes32" },
{ indexed: true, internalType: "address", name: "account", type: "address" },
{ indexed: true, internalType: "address", name: "sender", type: "address" }
],
name: "RoleRevoked",
type: "event"
},
{
inputs: [],
name: "DEFAULT_ADMIN_ROLE",
outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
stateMutability: "view",
type: "function"
},
{
inputs: [],
name: "actualRound",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ internalType: "uint256", name: "_round", type: "uint256" },
{ internalType: "uint256", name: "amount", type: "uint256" },
{ internalType: "bytes32[]", name: "proof", type: "bytes32[]" }
],
name: "claimReward",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "uint256[]", name: "_rounds", type: "uint256[]" },
{ internalType: "uint256[]", name: "amounts", type: "uint256[]" },
{ internalType: "bytes32[][]", name: "proofs", type: "bytes32[][]" }
],
name: "claimRewards",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "uint256", name: "", type: "uint256" },
{ internalType: "address", name: "", type: "address" }
],
name: "claimed",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }],
name: "getRoleAdmin",
outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "account", type: "address" }
],
name: "grantRole",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "account", type: "address" }
],
name: "hasRole",
outputs: [{ internalType: "bool", name: "", type: "bool" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "callerConfirmation", type: "address" }
],
name: "renounceRole",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "account", type: "address" }
],
name: "revokeRole",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [],
name: "rewardToken",
outputs: [{ internalType: "contract IERC20", name: "", type: "address" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "uint256", name: "_round", type: "uint256" }],
name: "setActualRound",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "uint256", name: "_round", type: "uint256" },
{ internalType: "bytes32", name: "_root", type: "bytes32" }
],
name: "setRootPerRound",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }],
name: "supportsInterface",
outputs: [{ internalType: "bool", name: "", type: "bool" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "uint256", name: "", type: "uint256" }],
name: "verifiersPerRound",
outputs: [{ internalType: "contract Verifier", name: "", type: "address" }],
stateMutability: "view",
type: "function"
}
];
// src/distribution/index.ts
var RewardDistribution = class {
constructor(_rewards) {
this.rewards = _rewards || {};
}
/**
* Sets the reward list.
* @param rewards The reward list to set.
*/
setRewardList(rewards) {
this.rewards = rewards;
}
/**
* Gets the reward contract address and ABI for a specific token.
* @param tokenSymbol The symbol of the token.
* @returns The reward contract address and ABI.
*/
async getRewardContract(tokenSymbol) {
tokenSymbol = tokenSymbol.toLowerCase();
const rewardContract = REWARD_DISTRIBUTOR_ADDRESSES[8453 /* BASE */][tokenSymbol];
if (!rewardContract) {
throw new Error(`No reward contract found for token ${tokenSymbol}`);
}
return {
address: rewardContract,
abi: REWARD_DISTRIBUTOR_ABI
};
}
/**
* Gets the Merkle tree for a specific token and round.
* @param tokenSymbol The symbol of the token.
* @param round The round number.
* @returns The Merkle tree for the specified token and round.
*/
async getTree(tokenSymbol, round) {
tokenSymbol = tokenSymbol.toLowerCase();
const treeData = this.rewards?.[tokenSymbol]?.[round];
if (!treeData) {
throw new Error(`No rewards found for token ${tokenSymbol}`);
}
const tree = StandardMerkleTree.of(
treeData.map((u) => [u.address, u.amount]),
["address", "uint256"]
);
return tree;
}
async getUserData(user, tokenSymbol, round) {
const tree = await this.getTree(tokenSymbol, round);
const indexOf = tree.dump().values.findIndex((data) => data.value.at(0)?.toLowerCase() === user.toLowerCase());
const userData = tree.dump().values.find((data) => data.value.at(0)?.toLowerCase() === user.toLowerCase())?.value?.reduce(
(acc, curr, index) => {
const keys = ["address", "amount"];
const key = keys[index];
if (!key) return acc;
acc[key] = curr;
return acc;
},
{}
);
return { userData, indexOf, tree };
}
/**
* Claims rewards for a user in multiple rounds.
* @param user The address of the user.
* @param rounds The array of round numbers.
* @param tokenSymbol The symbol of the token.
* @returns An array of transactions to be sent.
*/
async claimRewards({ user, rounds, tokenSymbol }) {
const txs = [];
for (const round of rounds) {
try {
const tx = await this.claimReward({ user, round, tokenSymbol });
txs.push(tx);
} catch (error) {
console.error(`Error claiming rewards for ${user} in round ${round}:`, error);
}
}
return txs.flat();
}
/**
* Claims the reward for a user in a specific round.
* @param user The address of the user.
* @param round The round number.
* @param tokenSymbol The symbol of the token.
* @returns An array of transactions to be sent.
*/
async claimReward({ user, round, tokenSymbol }) {
tokenSymbol = tokenSymbol.toLowerCase();
const { userData, indexOf, tree } = await this.getUserData(user, tokenSymbol, round);
if (!userData || !userData?.address) throw new Error(`User ${user} not found in the tree`);
const proof = tree.getProof(indexOf);
const distributor = await this.getRewardContract(tokenSymbol);
return [
{
tx: {
to: distributor.address,
data: encodeFunctionData({
abi: distributor.abi,
functionName: "claimReward",
args: [round, userData.amount, proof]
}),
value: "0"
},
amount: userData.amount
}
];
}
};
export {
RewardDistribution
};
//# sourceMappingURL=index.mjs.map