Skip to content

Commit

Permalink
feat: added APIs, unit tests for token permissions and integrated new…
Browse files Browse the repository at this point in the history
… logic to TokenPermissions UI component (#338) (#349)

dapp-feat: added APIs, unit tests for token permissions and integrated new logic to TokenPermissions UI component

Signed-off-by: Logan Nguyen <[email protected]>
  • Loading branch information
quiet-node authored Aug 18, 2023
1 parent dee7dcf commit 2ccb4d0
Show file tree
Hide file tree
Showing 5 changed files with 657 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
*
*/

import {
balanceOf,
erc20Mint,
getERC20TokenInformation,
handleErc20TokenPermissions,
} from '@/api/hedera/erc20-interactions';
import { Contract } from 'ethers';
import { balanceOf, erc20Mint, getERC20TokenInformation } from '@/api/hedera/erc20-interactions';

describe('getERC20TokenInformation', () => {
const expectedName = 'TokenName';
Expand Down Expand Up @@ -126,4 +131,155 @@ describe('balanceOf', () => {
expect(balanceOfRes.balanceOfRes).toBe('120');
expect(balanceOf).toBeCalled;
});

it('should fail with Invalid account address', async () => {
const balanceOfRes = await balanceOf(baseContract as unknown as Contract, '0x3619');

// assertion
expect(balanceOfRes.err).toBe('Invalid account address');
expect(balanceOfRes.balanceOfRes).toBeNull;
expect(balanceOf).toBeCalled;
});
});

describe('Token Permissions', () => {
const baseContract = {
approve: jest.fn(),
increaseAllowance: jest.fn(),
decreaseAllowance: jest.fn(),
decimals: jest.fn().mockResolvedValue(18),
allowance: jest.fn().mockResolvedValue('120'),
};

it('should execute erc20Approve', async () => {
const approveRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'approve',
'0x7a575266b2020e262e9b1ad4eba3014d63630095',
'',
120
);

// assertion
expect(approveRes.err).toBeNull;
expect(approveRes.approveRes).toBe(true);
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should fail erc20Approve with Invalid spender address', async () => {
const approveRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'approve',
'0x3619',
'',
120
);

// assertion
expect(approveRes.err).toBe('Invalid spender address');
expect(approveRes.approveRes).toBeNull;
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should execute erc20IncreaseAllowance', async () => {
const increaseAllowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'increaseAllowance',
'0x7a575266b2020e262e9b1ad4eba3014d63630095',
'',
120
);

// assertion
expect(increaseAllowanceRes.err).toBeNull;
expect(increaseAllowanceRes.increaseAllowanceRes).toBe(true);
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should fail erc20IncreaseAllowance with Invalid spender address', async () => {
const increaseAllowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'increaseAllowance',
'0x3619',
'',
120
);

// assertion
expect(increaseAllowanceRes.err).toBe('Invalid spender address');
expect(increaseAllowanceRes.increaseAllowanceRes).toBeNull;
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should execute erc20DecreaseAllowance', async () => {
const decreaseAllowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'decreaseAllowance',
'0x7a575266b2020e262e9b1ad4eba3014d63630095',
'',
120
);

// assertion
expect(decreaseAllowanceRes.err).toBeNull;
expect(decreaseAllowanceRes.decreaseAllowanceRes).toBe(true);
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should fail erc20DecreaseAllowance with Invalid spender address', async () => {
const decreaseAllowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'decreaseAllowance',
'0x3619',
'',
120
);

// assertion
expect(decreaseAllowanceRes.err).toBe('Invalid spender address');
expect(decreaseAllowanceRes.decreaseAllowanceRes).toBeNull;
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should execute erc20Allowance', async () => {
const allowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'allowance',
'0x7a575266b2020e262e9b1ad4eba3014d63630095',
'0x7a575266b2020e262e9b1ad4eba3014d63630012'
);

// assertion
expect(allowanceRes.err).toBeNull;
expect(allowanceRes.allowanceRes).toBe('120');
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should fail erc20Allowance with Invalid owner address', async () => {
const allowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'allowance',
'0x7a575266b2020e262e9b1ad4eba3014d63630012',
'0x3619'
);

// assertion
expect(allowanceRes.err).toBe('Invalid owner address');
expect(allowanceRes.allowanceRes).toBeNull;
expect(handleErc20TokenPermissions).toBeCalled;
});

it('should fail erc20Allowance with Invalid spender address', async () => {
const allowanceRes = await handleErc20TokenPermissions(
baseContract as unknown as Contract,
'allowance',
'0x3619',
'0x7a575266b2020e262e9b1ad4eba3014d63630012'
);

// assertion
expect(allowanceRes.err).toBe('Invalid spender address');
expect(allowanceRes.allowanceRes).toBeNull;
expect(handleErc20TokenPermissions).toBeCalled;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,62 @@ export const balanceOf = async (
return { err };
}
};

/**
* @dev handle executing APIs relate to Token Permissions
*
* @dev approve() sets `amount` as the allowance of `spenderAddress` over the caller's tokens
*
* @dev increaseAllowance() atomically increases the allowance granted to spender by the caller.
*
* @dev decreaseAllowance() atomically decreases the allowance granted to spender by the caller.
*
* @dev allowance() returns the remaining number of tokens that `spenerAddress` will be allowed to spend on behalf of `ownerAddress`
*
* @param baseContract: Contract
*
* @param method: 'approve' | 'allowance' | 'increaseAllowance' | 'decreaseAllowance'
*
* @param spenderAddress?: address
*
* @param owner?: address
*
* @param amount?: number
*
* @return Promise<ERC20MockSmartContractResult>
*/
export const handleErc20TokenPermissions = async (
baseContract: Contract,
method: 'approve' | 'allowance' | 'increaseAllowance' | 'decreaseAllowance',
spenderAddress: string,
ownerAddress?: string,
amount?: number
): Promise<ERC20MockSmartContractResult> => {
// sanitize params
if (ownerAddress && !isAddress(ownerAddress)) {
return { err: 'Invalid owner address' };
} else if (spenderAddress && !isAddress(spenderAddress)) {
return { err: 'Invalid spender address' };
}

// executing logic
try {
switch (method) {
case 'approve':
await baseContract.approve(spenderAddress, amount);
return { approveRes: true };
case 'increaseAllowance':
await baseContract.increaseAllowance(spenderAddress, amount);
return { increaseAllowanceRes: true };
case 'decreaseAllowance':
await baseContract.decreaseAllowance(spenderAddress, amount);
return { decreaseAllowanceRes: true };
case 'allowance':
const allowance = await baseContract.allowance(ownerAddress, spenderAddress);
return { allowanceRes: allowance.toString() };
}
} catch (err) {
console.error(err);
return { err };
}
};
19 changes: 19 additions & 0 deletions system-contract-dapp-playground/src/api/localStorage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,22 @@ export const getBalancesFromLocalStorage = () => {
return { err };
}
};

/**
* @dev get allowances from LocalStorage
*
* @return storageAllowances?: []
*
* @return err?
*/
export const getAllowancesFromLocalStorage = () => {
try {
const storageAllowances = localStorage.getItem('hedera_erc20_allowances');
return {
storageAllowances: storageAllowances ? JSON.parse(storageAllowances) : [],
};
} catch (err) {
console.error(err);
return { err };
}
};
Loading

0 comments on commit 2ccb4d0

Please sign in to comment.