Skip to content

Commit

Permalink
Add owr tranch function (#61)
Browse files Browse the repository at this point in the history
* Fixing objects and docs

* fix yarn

* fix lint

* prettier

* fix test for tranches

* prettier

* fix test

* final fix
  • Loading branch information
LukeHackett12 authored Oct 23, 2024
1 parent 5ac6e5e commit 2d6e7c3
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 27 deletions.
172 changes: 172 additions & 0 deletions src/abi/OWR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,175 @@ export const OWRFactoryContract = {
},
],
};

export const OWRContract = {
abi: [
{ inputs: [], stateMutability: 'nonpayable', type: 'constructor' },
{ inputs: [], name: 'InvalidDistribution_TooLarge', type: 'error' },
{
inputs: [],
name: 'InvalidTokenRecovery_InvalidRecipient',
type: 'error',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'uint256',
name: 'principalPayout',
type: 'uint256',
},
{
indexed: false,
internalType: 'uint256',
name: 'rewardPayout',
type: 'uint256',
},
{
indexed: false,
internalType: 'uint256',
name: 'pullFlowFlag',
type: 'uint256',
},
],
name: 'DistributeFunds',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'uint256',
name: 'amount',
type: 'uint256',
},
],
name: 'ReceiveETH',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'address',
name: 'recoveryAddressToken',
type: 'address',
},
{
indexed: false,
internalType: 'address',
name: 'recipient',
type: 'address',
},
{
indexed: false,
internalType: 'uint256',
name: 'amount',
type: 'uint256',
},
],
name: 'RecoverNonOWRecipientFunds',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'address',
name: 'account',
type: 'address',
},
{
indexed: false,
internalType: 'uint256',
name: 'amount',
type: 'uint256',
},
],
name: 'Withdrawal',
type: 'event',
},
{
inputs: [],
name: 'claimedPrincipalFunds',
outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'distributeFunds',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [],
name: 'distributeFundsPull',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [],
name: 'fundsPendingWithdrawal',
outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
name: 'getPullBalance',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'getTranches',
outputs: [
{
internalType: 'address',
name: 'principalRecipient',
type: 'address',
},
{ internalType: 'address', name: 'rewardRecipient', type: 'address' },
{
internalType: 'uint256',
name: 'amountOfPrincipalStake',
type: 'uint256',
},
],
stateMutability: 'pure',
type: 'function',
},
{
inputs: [
{ internalType: 'address', name: 'nonOWRToken', type: 'address' },
{ internalType: 'address', name: 'recipient', type: 'address' },
],
name: 'recoverFunds',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [],
name: 'recoveryAddress',
outputs: [{ internalType: 'address', name: '', type: 'address' }],
stateMutability: 'pure',
type: 'function',
},
{
inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
name: 'withdraw',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
],
};
23 changes: 23 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
type OperatorPayload,
type TotalSplitPayload,
type ClusterValidator,
type ETH_ADDRESS,
type OWRTranches,
} from './types.js';
import { clusterConfigOrDefinitionHash } from './verification/common.js';
import { validatePayload } from './ajv.js';
Expand All @@ -42,6 +44,7 @@ import {
formatSplitRecipients,
handleDeployOWRAndSplitter,
predictSplitterAddress,
getOWRTranches,
} from './splitHelpers.js';
import { isContractAvailable } from './utils.js';
export * from './types.js';
Expand Down Expand Up @@ -338,6 +341,26 @@ export class Client extends Base {
};
}

/**
* Read OWR Tranches.
*
* @remarks
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
* and not pushed to version control.
*
* @param {ETH_ADDRESS} owrAddress - Address of the Deployed OWR Contract
* @returns {Promise<OWRTranches>} owr tranch information about principal and reward reciepient, as well as the principal amount
*
*/
async getOWRTranches(owrAddress: ETH_ADDRESS): Promise<OWRTranches> {
if (!this.signer) {
throw new Error('Signer is required in getOWRTranches');
}

const signer = this.signer;
return await getOWRTranches({ owrAddress, signer });
}

/**
* Creates a cluster definition which contains cluster configuration.
* @param {ClusterPayload} newCluster - The new unique cluster.
Expand Down
21 changes: 20 additions & 1 deletion src/splitHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
type OWRTranches,
type ClusterValidator,
type ETH_ADDRESS,
type SplitRecipient,
Expand All @@ -10,7 +11,7 @@ import {
ZeroAddress,
type Signer,
} from 'ethers';
import { OWRFactoryContract } from './abi/OWR';
import { OWRContract, OWRFactoryContract } from './abi/OWR';
import { splitMainEthereumAbi } from './abi/SplitMain';
import { MultiCallContract } from './abi/Multicall';
import { CHAIN_CONFIGURATION } from './constants';
Expand Down Expand Up @@ -237,6 +238,7 @@ export const deploySplitterContract = async ({
throw e;
}
};

export const deploySplitterAndOWRContracts = async ({
owrArgs,
splitterArgs,
Expand Down Expand Up @@ -297,6 +299,23 @@ export const deploySplitterAndOWRContracts = async ({
}
};

export const getOWRTranches = async ({
owrAddress,
signer,
}: {
owrAddress: ETH_ADDRESS;
signer: Signer;
}): Promise<OWRTranches> => {
const owrContract = new Contract(owrAddress, OWRContract.abi, signer);
const res = await owrContract.getTranches();

return {
principalRecipient: res.principalRecipient,
rewardRecipient: res.rewardRecipient,
amountOfPrincipalStake: res.amountOfPrincipalStake,
};
};

export const multicall = async (
calls: Call[],
signer: Signer,
Expand Down
14 changes: 14 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,20 @@ export interface RewardsSplitPayload extends TotalSplitPayload {
recoveryAddress?: string;
}

/**
* OWR Tranches
*/
export type OWRTranches = {
/** Address that will reclaim validator principal after exit. */
principalRecipient: ETH_ADDRESS;

/** Address that will reclaim validator rewards during operation. */
rewardRecipient: ETH_ADDRESS;

/** Amount of principal staked. */
amountOfPrincipalStake: number;
};

/**
* Unsigned DV Builder Registration Message
*/
Expand Down
55 changes: 41 additions & 14 deletions test/sdk-package-test/cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,46 +133,73 @@ describe('Cluster Definition', () => {
});

it('should deploy OWR and Splitter', async () => {
const signerAddress = await randomSigner.getAddress();
const secondRandomSignerAddress = await secondRandomSigner.getAddress();
// new splitter
const { withdrawal_address, fee_recipient_address } =
await client.createObolRewardsSplit({
await client.createObolTotalSplit({
splitRecipients: [
{ account: signerAddress, percentAllocation: 39 },
{ account: secondRandomSignerAddress, percentAllocation: 39.9 },
{
account: '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966',
percentAllocation: 60,
},
],
principalRecipient: '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966',
etherAmount: 2,
recoveryAddress: '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966',
});

// same splitter
const contractsWithSameFeeRecipientAddress =
await client.createObolRewardsSplit({
await client.createObolTotalSplit({
splitRecipients: [
{ account: signerAddress, percentAllocation: 39 },
{ account: secondRandomSignerAddress, percentAllocation: 39.9 },
{
account: '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966',
percentAllocation: 60,
},
],
principalRecipient: '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966',
etherAmount: 2,
});

expect(withdrawal_address.length).toEqual(42);
expect(fee_recipient_address.length).toEqual(42);
expect(
contractsWithSameFeeRecipientAddress.withdrawal_address.length,
).toEqual(42);

expect(fee_recipient_address.toLowerCase()).toEqual(
withdrawal_address.toLowerCase(),
);

expect(fee_recipient_address.toLowerCase()).toEqual(
contractsWithSameFeeRecipientAddress.fee_recipient_address.toLowerCase(),
);
});

it('should deploy OWR and splitter and get tranches', async () => {
const secondRandomSignerAddress = await secondRandomSigner.getAddress();
const principalRecipient = '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966';

// new splitter
const { withdrawal_address, fee_recipient_address } =
await client.createObolRewardsSplit({
splitRecipients: [
{ account: secondRandomSignerAddress, percentAllocation: 39 },
{
account: principalRecipient,
percentAllocation: 60,
},
],
principalRecipient: principalRecipient,
etherAmount: 2,
distributorFee: 2,
controllerAddress: principalRecipient,
});

const res = await client.getOWRTranches(withdrawal_address);

expect(res.principalRecipient.toLowerCase()).toEqual(
principalRecipient.toLowerCase(),
);
expect(res.rewardRecipient.toLowerCase()).toEqual(
fee_recipient_address.toLowerCase(),
);
expect(res.amountOfPrincipalStake).toEqual(BigInt(2000000000000000000));
});

it('should deploy OWR and Splitter with a controller address and a distributorFee', async () => {
const signerAddress = await randomSigner.getAddress();
// new splitter
Expand Down
Loading

0 comments on commit 2d6e7c3

Please sign in to comment.