Skip to content

Commit 439a1f2

Browse files
authored
Merge pull request #57 from SetProtocol/justin_chen-add-batch-methods
Add batch methods for balance and allowance checking
2 parents 3ef4b25 + a405ec3 commit 439a1f2

12 files changed

+229
-16
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@setprotocol/set.js",
3-
"version": "2.1.1",
3+
"version": "2.1.2",
44
"description": "A javascript library for interacting with the Set Protocol v2",
55
"keywords": [
66
"set.js",
@@ -57,7 +57,7 @@
5757
"@0xproject/types": "^1.1.4",
5858
"@0xproject/typescript-typings": "^3.0.2",
5959
"@0xproject/utils": "^2.0.2",
60-
"@setprotocol/set-protocol-v2": "0.0.19",
60+
"@setprotocol/set-protocol-v2": "0.0.31",
6161
"@truffle/contract": "^4.2.13",
6262
"@types/chai-as-promised": "^7.1.3",
6363
"@types/jest": "^26.0.5",

src/api/ERC20API.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ import Assertions from '../assertions';
3434
export default class ERC20API {
3535
private assert: Assertions;
3636
private erc20Wrapper: ERC20Wrapper;
37-
38-
public constructor(provider: Provider, assertions?: Assertions) {
37+
public constructor(
38+
provider: Provider,
39+
assertions?: Assertions
40+
) {
3941
this.erc20Wrapper = new ERC20Wrapper(provider);
4042
this.assert = assertions || new Assertions();
4143
}

src/api/SetTokenAPI.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,52 @@ export default class SetTokenAPI {
196196
return await this.protocolViewerWrapper.batchFetchManagers(tokenAddresses);
197197
}
198198

199+
/**
200+
* Batch fetches balances for a list of tokens for a given owner
201+
* @param tokenAddresses Array of ERC20 token addresses
202+
* @param userAddress Address of the user
203+
* @returns The balances of the ERC20 tokens for the user in array of BigNumbers format
204+
*/
205+
public async batchFetchBalancesOfAsync(tokenAddresses: Address[], userAddress: Address): Promise<BigNumber[]> {
206+
this.assert.schema.isValidAddress('userAddress', userAddress);
207+
const ownerAddresses = tokenAddresses.map(tokenAddress => {
208+
this.assert.schema.isValidAddress('tokenAddress', tokenAddress);
209+
return userAddress;
210+
});
211+
212+
return await this.protocolViewerWrapper.batchFetchBalancesOf(tokenAddresses, ownerAddresses);
213+
}
214+
215+
/**
216+
* Batch fetches allowances for a list of tokens for a given owners/spenders
217+
* @param tokenAddresses Array of ERC20 token addresses
218+
* @param ownerAddress Owner address to check for
219+
* @param spenderAddress Spender address to check for
220+
* @returns The allowances of the ERC20 tokens for the owner, spender in array of BigNumbers format
221+
*/
222+
public async batchFetchAllowancesAsync(
223+
tokenAddresses: Address[],
224+
ownerAddress: Address,
225+
spenderAddress: Address
226+
): Promise<BigNumber[]> {
227+
this.assert.schema.isValidAddress('ownerAddress', ownerAddress);
228+
this.assert.schema.isValidAddress('spenderAddress', spenderAddress);
229+
const ownerAddresses = [];
230+
const spenderAddresses = [];
231+
232+
tokenAddresses.forEach(tokenAddress => {
233+
this.assert.schema.isValidAddress('tokenAddress', tokenAddress);
234+
ownerAddresses.push(ownerAddress);
235+
spenderAddresses.push(spenderAddress);
236+
});
237+
238+
return await this.protocolViewerWrapper.batchFetchAllowances(
239+
tokenAddresses,
240+
ownerAddresses,
241+
spenderAddresses
242+
);
243+
}
244+
199245
/**
200246
* Gets the controller address of a target Set Token.
201247
*

src/wrappers/set-protocol-v2/ProtocolViewerWrapper.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { Address } from '@setprotocol/set-protocol-v2/utils/types';
2121

2222
import ContractWrapper from './ContractWrapper';
2323
import { SetDetails, StreamingFeeInfo } from '../../types';
24+
import { BigNumber } from 'ethers/lib/ethers';
2425

2526
/**
2627
* @title ProtocolViewerWrapper
@@ -46,7 +47,7 @@ export default class ProtocolViewerWrapper {
4647
/**
4748
* Fetches the managers of set tokens
4849
*
49-
* @param tokenAddresses Addresses of ERC20 contracts to check balance for
50+
* @param tokenAddresses Addresses of ERC20 contracts to check managers for
5051
* @param callerAddress Address to use as the caller (optional)
5152
*/
5253
public async batchFetchManagers(
@@ -64,7 +65,7 @@ export default class ProtocolViewerWrapper {
6465
/**
6566
* Fetches the streaming fee info of set tokens
6667
*
67-
* @param tokenAddresses Addresses of ERC20 contracts to check balance for
68+
* @param tokenAddresses Addresses of ERC20 contracts to check streaming fee for
6869
* @param callerAddress Address to use as the caller (optional)
6970
*/
7071
public async batchFetchStreamingFeeInfo(
@@ -82,6 +83,55 @@ export default class ProtocolViewerWrapper {
8283
);
8384
}
8485

86+
/**
87+
* Fetches the balance of list of set tokens and user addresses
88+
*
89+
* @param tokenAddresses Addresses of ERC20 contracts to check balance for
90+
* @param userAddresses Addresses of users to check balances for matched up with token index
91+
* @param callerAddress Address to use as the caller (optional)
92+
*/
93+
public async batchFetchBalancesOf(
94+
tokenAddresses: Address[],
95+
userAddresses: Address[],
96+
callerAddress?: Address,
97+
): Promise<BigNumber[]> {
98+
const protocolViewerInstance = await this.contracts.loadProtocolViewerContractAsync(
99+
this.protocolViewerAddress,
100+
(this.provider as JsonRpcProvider).getSigner(callerAddress)
101+
);
102+
103+
return await protocolViewerInstance.batchFetchBalancesOf(
104+
tokenAddresses,
105+
userAddresses
106+
);
107+
}
108+
109+
/**
110+
* Fetches the allowances of list of set tokens and owner/spender addresses
111+
*
112+
* @param tokenAddresses Addresses of ERC20 contracts to check alloances for
113+
* @param ownerAddresses Addresses of owners of token matched up with token index
114+
* @param spenderAddresses Addresses of spenders of token matched up with token index
115+
* @param callerAddress Address to use as the caller (optional)
116+
*/
117+
public async batchFetchAllowances(
118+
tokenAddresses: Address[],
119+
ownerAddresses: Address[],
120+
spenderAddresses: Address[],
121+
callerAddress?: Address,
122+
): Promise<BigNumber[]> {
123+
const protocolViewerInstance = await this.contracts.loadProtocolViewerContractAsync(
124+
this.protocolViewerAddress,
125+
(this.provider as JsonRpcProvider).getSigner(callerAddress)
126+
);
127+
128+
return await protocolViewerInstance.batchFetchAllowances(
129+
tokenAddresses,
130+
ownerAddresses,
131+
spenderAddresses
132+
);
133+
}
134+
85135
/**
86136
* Fetches the details of the SetToken. Accepts an array of module addresses and returns
87137
* the initialization statuses of each of the modules for the SetToken

test/api/SetTokenAPI.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ jest.mock('@src/wrappers/set-protocol-v2/ProtocolViewerWrapper', () => {
4949
batchFetchManagers: jest.fn().mockImplementationOnce(() => {
5050
return ['0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5'];
5151
}),
52+
batchFetchBalancesOf: jest.fn().mockImplementationOnce(() => {
53+
return ['10000000000000'];
54+
}),
55+
batchFetchAllowances: jest.fn().mockImplementationOnce(() => {
56+
return ['311173045478743'];
57+
}),
5258
batchFetchDetails: jest.fn().mockImplementationOnce(() => {
5359
return [{
5460
name: 'DeFi Pulse Index',
@@ -68,6 +74,8 @@ describe('SetTokenAPI', () => {
6874
let streamingFeeModuleAddress: Address;
6975
let protocolViewerAddress: Address;
7076
let setTokenCreatorAddress: Address;
77+
let ownerAddress: Address;
78+
let spenderAddress: Address;
7179
let setTokenAPI: SetTokenAPI;
7280
let setTokenWrapper: SetTokenWrapper;
7381
let setTokenCreatorWrapper: SetTokenCreatorWrapper;
@@ -77,6 +85,8 @@ describe('SetTokenAPI', () => {
7785
streamingFeeModuleAddress,
7886
protocolViewerAddress,
7987
setTokenCreatorAddress,
88+
ownerAddress,
89+
spenderAddress,
8090
] = await provider.listAccounts();
8191

8292
setTokenAPI = new SetTokenAPI(provider, protocolViewerAddress, streamingFeeModuleAddress, setTokenCreatorAddress);
@@ -254,6 +264,45 @@ describe('SetTokenAPI', () => {
254264
});
255265
});
256266

267+
describe('#batchFetchBalancesOfAsync', () => {
268+
let subjectSetTokenAddresses: Address[];
269+
270+
beforeEach(async () => {
271+
subjectSetTokenAddresses = ['0xEC0815AA9B462ed4fC84B5dFc43Fd2a10a54B569'];
272+
});
273+
274+
async function subject(): Promise<BigNumber[]> {
275+
return await setTokenAPI.batchFetchBalancesOfAsync(
276+
subjectSetTokenAddresses,
277+
ownerAddress
278+
);
279+
}
280+
281+
it('should call the ProtocolViewerWrapper with correct params', async () => {
282+
await subject();
283+
});
284+
});
285+
286+
describe('#batchFetchAllowancesAsync', () => {
287+
let subjectSetTokenAddresses: Address[];
288+
289+
beforeEach(async () => {
290+
subjectSetTokenAddresses = ['0xEC0815AA9B462ed4fC84B5dFc43Fd2a10a54B569'];
291+
});
292+
293+
async function subject(): Promise<BigNumber[]> {
294+
return await setTokenAPI.batchFetchAllowancesAsync(
295+
subjectSetTokenAddresses,
296+
ownerAddress,
297+
spenderAddress
298+
);
299+
}
300+
301+
it('should call the ProtocolViewerWrapper with correct params', async () => {
302+
await subject();
303+
});
304+
});
305+
257306
describe('#getControllerAddressAsync', () => {
258307
let subjectSetTokenAddress: Address;
259308

test/wrappers/set-protocol-v2/BasicIssuanceModuleWrapper.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Address } from '@setprotocol/set-protocol-v2/utils/types';
55
import { ADDRESS_ZERO, ZERO } from '@setprotocol/set-protocol-v2/dist/utils/constants';
66
import { Blockchain, ether, bitcoin } from '@setprotocol/set-protocol-v2/dist/utils/common';
77
import DeployHelper from '@setprotocol/set-protocol-v2/dist/utils/deploys';
8-
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures';
8+
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures/systemFixture';
99
import {
1010
BasicIssuanceModule,
1111
SetToken,

test/wrappers/set-protocol-v2/DebtIssuanceModuleWrapper.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
preciseMulCeil,
1212
} from '@setprotocol/set-protocol-v2/dist/utils/common';
1313
import DeployHelper from '@setprotocol/set-protocol-v2/dist/utils/deploys';
14-
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures';
14+
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures/systemFixture';
1515
import {
1616
DebtIssuanceModule,
1717
SetToken,

test/wrappers/set-protocol-v2/NavIssuanceModuleWrapper.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
getExpectedRedeemPositionUnit
2020
} from '@setprotocol/set-protocol-v2/dist/utils/common';
2121
import DeployHelper from '@setprotocol/set-protocol-v2/dist/utils/deploys';
22-
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures';
22+
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures/systemFixture';
2323
import { ERC20__factory } from '@setprotocol/set-protocol-v2/dist/typechain/factories/ERC20__factory';
2424
import {
2525
NAVIssuanceModule,

test/wrappers/set-protocol-v2/ProtocolViewerWrapper.spec.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Address, StreamingFeeState } from '@setprotocol/set-protocol-v2/utils/t
55
import { ADDRESS_ZERO, ZERO, ONE_YEAR_IN_SECONDS } from '@setprotocol/set-protocol-v2/dist/utils/constants';
66
import { Blockchain, ether, getStreamingFee } from '@setprotocol/set-protocol-v2/dist/utils/common';
77
import DeployHelper from '@setprotocol/set-protocol-v2/dist/utils/deploys';
8-
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures';
8+
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures/systemFixture';
99
import {
1010
ProtocolViewer,
1111
SetToken,
@@ -122,6 +122,72 @@ describe('ProtocolViewerWrapper', () => {
122122
});
123123
});
124124

125+
describe('#batchFetchBalancesOf', () => {
126+
let subjectTokenAddresses: Address[];
127+
let subjectOwnerAddresses: Address[];
128+
129+
beforeEach(async () => {
130+
subjectTokenAddresses = [setup.usdc.address, setup.dai.address];
131+
subjectOwnerAddresses = [owner, managerOne];
132+
});
133+
134+
async function subject(): Promise<any> {
135+
return protocolViewerWrapper.batchFetchBalancesOf(subjectTokenAddresses, subjectOwnerAddresses);
136+
}
137+
138+
it('should return the correct set details', async () => {
139+
const [balanceOne, balanceTwo]: any = await subject();
140+
141+
const expectedUSDCBalance = await setup.usdc.connect(provider.getSigner(owner)).balanceOf(owner);
142+
expect(balanceOne.toString()).to.eq(expectedUSDCBalance.toString());
143+
144+
const expectedDAIBalance = await setup.dai.connect(provider.getSigner(owner)).balanceOf(managerOne);
145+
expect(balanceTwo.toString()).to.eq(expectedDAIBalance.toString());
146+
});
147+
});
148+
149+
describe('#batchFetchAllowances', () => {
150+
let subjectTokenAddresses: Address[];
151+
let subjectOwnerAddresses: Address[];
152+
let subjectSpenderAddresses: Address[];
153+
154+
beforeEach(async () => {
155+
const usdcApprovalAmount = ether(3);
156+
await setup.usdc.approve(managerOne, usdcApprovalAmount);
157+
158+
const daiApprovalAmount = ether(2);
159+
await setup.dai.approve(managerTwo, daiApprovalAmount);
160+
161+
subjectTokenAddresses = [setup.usdc.address, setup.dai.address];
162+
subjectOwnerAddresses = [owner, owner];
163+
subjectSpenderAddresses = [managerOne, managerTwo];
164+
});
165+
166+
async function subject(): Promise<any> {
167+
return protocolViewerWrapper.batchFetchAllowances(
168+
subjectTokenAddresses,
169+
subjectOwnerAddresses,
170+
subjectSpenderAddresses
171+
);
172+
}
173+
174+
it('should return the correct allowances', async () => {
175+
const [allowanceOne, allowanceTwo]: any = await subject();
176+
177+
const expectedUSDCAllowance = await setup.usdc.allowance(
178+
owner,
179+
managerOne
180+
);
181+
expect(allowanceOne.toString()).to.eq(expectedUSDCAllowance.toString());
182+
183+
const expectedDAIAllowance = await setup.dai.allowance(
184+
owner,
185+
managerTwo
186+
);
187+
expect(allowanceTwo.toString()).to.eq(expectedDAIAllowance.toString());
188+
});
189+
});
190+
125191
describe('#batchFetchStreamingFeeInfo', () => {
126192
let subjectSetTokens: Address[];
127193

test/wrappers/set-protocol-v2/StreamingFeeModuleWrapper.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
preciseMul,
1212
} from '@setprotocol/set-protocol-v2/dist/utils/common';
1313
import DeployHelper from '@setprotocol/set-protocol-v2/dist/utils/deploys';
14-
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures';
14+
import { SystemFixture } from '@setprotocol/set-protocol-v2/dist/utils/fixtures/systemFixture';
1515
import {
1616
BasicIssuanceModule,
1717
StreamingFeeModule,

0 commit comments

Comments
 (0)