Skip to content

Commit

Permalink
feat: add in GhoTokenService for totalSupply & facilitator info (#444)
Browse files Browse the repository at this point in the history
* feat: add in GhoTokenService and getFacilitatorBucket

* fix: typo

* feat: add in more utils for GhoTokenService
  • Loading branch information
drewcook authored Nov 2, 2022
1 parent c0f314c commit b727e9c
Show file tree
Hide file tree
Showing 8 changed files with 2,728 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ describe('GhoDiscountRateStrategyService', () => {

describe('Create new GhoDiscountRateStrategyService', () => {
it('Expects to be initialized correctly', () => {
// Create instance
const instance = new GhoDiscountRateStrategyService(
correctProvider,
DISCOUNT_RATE_STRATEGY_ADDRESS,
);

// Assert it
expect(instance).toBeInstanceOf(GhoDiscountRateStrategyService);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import BaseService from '../commons/BaseService';
import { GhoDiscountRateStrategy__factory } from './typechain/GhoDiscountRateStrategy__factory';
import type { IGhoDiscountRateStrategy } from './typechain/IGhoDiscountRateStrategy';

export interface GhoDiscountRateServiceInterface {
interface IGhoDiscountRateStrategyService {
calculateDiscountRate: (
ghoDebtTokenBalance: BigNumberish,
skAaveBalance: BigNumberish,
Expand All @@ -16,7 +16,7 @@ export interface GhoDiscountRateServiceInterface {
*/
export class GhoDiscountRateStrategyService
extends BaseService<IGhoDiscountRateStrategy>
implements GhoDiscountRateServiceInterface
implements IGhoDiscountRateStrategyService
{
readonly ghoDiscountRateStrategyAddress: string;

Expand Down
150 changes: 150 additions & 0 deletions packages/contract-helpers/src/gho/GhoTokenService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { constants, BigNumber, providers } from 'ethers';
import { valueToWei } from '../commons/utils';
import { GhoTokenService } from './GhoTokenService';
import { GhoToken } from './typechain/GhoToken';
import { GhoToken__factory } from './typechain/GhoToken__factory';
import { IGhoToken } from './typechain/IGhoToken';

jest.mock('../commons/gasStation', () => {
return {
__esModule: true,
estimateGasByNetwork: jest
.fn()
.mockImplementation(async () => Promise.resolve(BigNumber.from(1))),
estimateGas: jest.fn(async () => Promise.resolve(BigNumber.from(1))),
};
});

// Helper for contract call arguments
const convertToBN = (n: string) => valueToWei(n, 18);

describe('GhoTokenService', () => {
const GHO_TOKEN_ADDRESS = constants.AddressZero;
const correctProvider: providers.Provider = new providers.JsonRpcProvider();

// Mocking
jest
.spyOn(correctProvider, 'getGasPrice')
.mockImplementation(async () => Promise.resolve(BigNumber.from(1)));

afterEach(() => jest.clearAllMocks());

describe('Create new GhoTokenService', () => {
it('Expects to be initialized correctly', () => {
// Create Instance
const instance = new GhoTokenService(correctProvider, GHO_TOKEN_ADDRESS);

// Assert it
expect(instance).toBeInstanceOf(GhoTokenService);
});
});

describe('totalSupply', () => {
it('should return the total supply of GHO tokens', async () => {
// Create Instance
const contract = new GhoTokenService(correctProvider, GHO_TOKEN_ADDRESS);

// Setup
const mockTotalSupply = convertToBN('10000000'); // 10M

// Mock it
const spy = jest.spyOn(GhoToken__factory, 'connect').mockReturnValue({
totalSupply: async () => Promise.resolve(mockTotalSupply),
} as unknown as GhoToken);

// Call it
const result = await contract.totalSupply();

// Assert it
expect(spy).toHaveBeenCalled();
expect(spy).toBeCalledTimes(1);
expect(result).toEqual(mockTotalSupply);
});
});

describe('getFacilitatorsList', () => {
it('should return the list of facilitators as an array of addresses', async () => {
// Create instance
const contract = new GhoTokenService(correctProvider, GHO_TOKEN_ADDRESS);

// Setup
const faciliatorAddress1: string = constants.AddressZero;
const faciliatorAddress2: string = constants.AddressZero;
const mockFacilitatorsList: string[] = [
faciliatorAddress1,
faciliatorAddress2,
];

// Mock it
const spy = jest.spyOn(GhoToken__factory, 'connect').mockReturnValue({
getFacilitatorsList: async () => Promise.resolve(mockFacilitatorsList),
} as unknown as GhoToken);

// Call it
const result = await contract.getFacilitatorsList();

// Assert it
expect(spy).toHaveBeenCalled();
expect(spy).toBeCalledTimes(1);
expect(result).toEqual(mockFacilitatorsList);
});
});

describe('getFacilitator', () => {
it('should return the facilitator instance for the provided facilitator address', async () => {
// Create instance
const contract = new GhoTokenService(correctProvider, GHO_TOKEN_ADDRESS);

// Setup
const faciliatorAddress: string = constants.AddressZero;
const mockBucket: IGhoToken.BucketStruct = {
maxCapacity: convertToBN('1000'),
level: convertToBN('500'),
};
const mockFacilitator: IGhoToken.FacilitatorStruct = {
bucket: mockBucket,
label: 'Aave Facilitator',
};

// Mock it
const spy = jest.spyOn(GhoToken__factory, 'connect').mockReturnValue({
getFacilitator: async () => Promise.resolve(mockFacilitator),
} as unknown as GhoToken);

// Call it
const result = await contract.getFacilitator(faciliatorAddress);

// Assert it
expect(spy).toHaveBeenCalled();
expect(spy).toBeCalledTimes(1);
expect(result).toEqual(mockFacilitator);
});
});

describe('getFacilitatorBucket', () => {
it('should return the bucket instance for the provided facilitator address', async () => {
// Create instance
const contract = new GhoTokenService(correctProvider, GHO_TOKEN_ADDRESS);

// Setup
const faciliatorAddress: string = constants.AddressZero;
const mockBucket: IGhoToken.BucketStruct = {
maxCapacity: convertToBN('1000'),
level: convertToBN('500'),
};

// Mock it
const spy = jest.spyOn(GhoToken__factory, 'connect').mockReturnValue({
getFacilitatorBucket: async () => Promise.resolve(mockBucket),
} as unknown as GhoToken);

// Call it
const result = await contract.getFacilitatorBucket(faciliatorAddress);

// Assert it
expect(spy).toHaveBeenCalled();
expect(spy).toBeCalledTimes(1);
expect(result).toEqual(mockBucket);
});
});
});
75 changes: 75 additions & 0 deletions packages/contract-helpers/src/gho/GhoTokenService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { BigNumber, providers } from 'ethers';
import BaseService from '../commons/BaseService';
import type { GhoToken } from './typechain/GhoToken';
import { GhoToken__factory } from './typechain/GhoToken__factory';
import type { IGhoToken } from './typechain/IGhoToken';

interface IGhoTokenService {
totalSupply: () => Promise<BigNumber>;
getFacilitatorsList: () => Promise<string[]>;
getFacilitator: (
facilitatorAddress: string,
) => Promise<IGhoToken.FacilitatorStruct>;
getFacilitatorBucket: (
facilitatorAddress: string,
) => Promise<IGhoToken.BucketStruct>;
}

/**
* The service for interacting with the GhoToken.sol smart contract.
* This contract controls operations minting & burning the native GHO token as well as facilitator management.
* https://github.com/aave/gho/blob/main/src/contracts/gho/GhoToken.sol
*/
export class GhoTokenService
extends BaseService<GhoToken>
implements IGhoTokenService
{
readonly ghoTokenAddress: string;

constructor(provider: providers.Provider, ghoTokenAddress: string) {
super(provider, GhoToken__factory);
this.ghoTokenAddress = ghoTokenAddress;
}

/**
* Gets the total supply for the GHO token. This is the sum of all facilitators' current bucket levels
* @returns - A BigNumber representing the total supply of GHO
*/
public async totalSupply() {
const contract = this.getContractInstance(this.ghoTokenAddress);
const result = await contract.totalSupply();
return result;
}

/**
* Gets the full list of facilitators for the GHO token
* @returns - An array of facilitator addresses, which can be used for querying in more detail
*/
public async getFacilitatorsList() {
const contract = this.getContractInstance(this.ghoTokenAddress);
const result = await contract.getFacilitatorsList();
return result;
}

/**
* Gets the instance for a given facilitator
* @param facilitatorAddress - The address for the currently deployed contract for the facilitator being queried
* @returns - The instance of the facilitator, which contains `bucket` and `label` fields
*/
public async getFacilitator(facilitatorAddress: string) {
const contract = this.getContractInstance(this.ghoTokenAddress);
const result = await contract.getFacilitator(facilitatorAddress);
return result;
}

/**
* Gets the bucket instance for a given facilitator
* @param facilitatorAddress - The address for the currently deployed contract for the facilitator being queried
* @returns - The instance of the facilitator bucket, which contains `maxCapacity` and `level` fields
*/
public async getFacilitatorBucket(facilitatorAddress: string) {
const contract = this.getContractInstance(this.ghoTokenAddress);
const result = await contract.getFacilitatorBucket(facilitatorAddress);
return result;
}
}
Loading

0 comments on commit b727e9c

Please sign in to comment.