Skip to content

Commit

Permalink
Handle permit for unifi tokens internally when depositing
Browse files Browse the repository at this point in the history
  • Loading branch information
9inpachi committed Oct 14, 2024
1 parent d6f3438 commit 0be1bec
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 31 deletions.
39 changes: 31 additions & 8 deletions lib/contracts/handlers/nucleus-teller-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { mockAccount, testingUtils } from '../../../test/setup-tests';
import { NUCLEUS_TELLER_ABIS } from '../abis/nucleus-teller-abis';
import { NucleusTellerHandler } from './nucleus-teller-handler';
import { generateAddress } from '../../../test/mocks/address';
import { Token, TOKENS_ADDRESSES } from '../tokens';
import { Token, TOKENS_ADDRESSES, UnifiToken } from '../tokens';
import { isHash } from 'viem';
import { mockPermitSignature } from '../../../test/mocks/permit-signature';

describe('NucleusBoringVaultHandler', () => {
const contractTestingUtils = testingUtils.generateContractUtils(
Expand Down Expand Up @@ -55,15 +56,37 @@ describe('NucleusBoringVaultHandler', () => {
expect(isPaused).toBe(mockIsPaused);
});

it('should deposit without a permit', async () => {
it('should deposit with preapproval', async () => {
contractTestingUtils.mockTransaction('deposit');

const { transact, estimate } = handler.deposit(
mockAccount,
Token.pufETH,
100n,
0n,
);
const { transact, estimate } = await handler.deposit({
account: mockAccount,
token: Token.pufETH,
unifiToken: UnifiToken.unifiETH,
amount: 100n,
minimumMint: 0n,
isPreapproved: true,
});

expect(typeof (await estimate())).toBe('bigint');
expect(isHash(await transact())).toBe(true);
});

it('should deposit with generated permit', async () => {
contractTestingUtils.mockTransaction('depositWithPermit');
jest
.spyOn((handler as any).erc20PermitHandler, 'getPermitSignature')
.mockReturnValue(Promise.resolve(mockPermitSignature));

const { transact, estimate } = await handler.deposit({
account: mockAccount,
token: Token.pufETH,
unifiToken: UnifiToken.unifiETH,
amount: 100n,
minimumMint: 0n,
// This is set by default.
// isPreapproved: false,
});

expect(typeof (await estimate())).toBe('bigint');
expect(isHash(await transact())).toBe(true);
Expand Down
100 changes: 78 additions & 22 deletions lib/contracts/handlers/nucleus-teller-handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* istanbul ignore file */

import {
WalletClient,
PublicClient,
Expand All @@ -10,7 +8,17 @@ import {
import { Chain, VIEM_CHAINS, ViemChain } from '../../chains/constants';
import { CONTRACT_ADDRESSES } from '../addresses';
import { NUCLEUS_TELLER_ABIS } from '../abis/nucleus-teller-abis';
import { Token, TOKENS_ADDRESSES } from '../tokens';
import { Token, TOKENS_ADDRESSES, UnifiToken } from '../tokens';
import { ERC20PermitHandler } from './erc20-permit-handler';

export type DepositParams = {
account: Address;
token: Token;
unifiToken: UnifiToken;
amount: bigint;
minimumMint: bigint;
isPreapproved?: boolean;
};

export type DepositWithPermitParams = {
account: Address;
Expand All @@ -28,6 +36,7 @@ export type DepositWithPermitParams = {
*/
export class NucleusTellerHandler {
private viemChain: ViemChain;
private erc20PermitHandler: ERC20PermitHandler;

/**
* Create the handler for processing tokens.
Expand All @@ -44,6 +53,11 @@ export class NucleusTellerHandler {
private publicClient: PublicClient,
) {
this.viemChain = VIEM_CHAINS[chain];
this.erc20PermitHandler = new ERC20PermitHandler(
chain,
walletClient,
publicClient,
);
}

/**
Expand Down Expand Up @@ -111,38 +125,80 @@ export class NucleusTellerHandler {
}

/**
* Deposit the given token for staking.
* Deposit the given token for staking. This doesn't make the
* transaction but returns two methods namely `transact` and
* `estimate`.
*
* @param walletAddress Address of the caller of the transaction.
* @param token Token to deposit.
* @param amount Amount of the token to deposit.
* @param minimumMint Minimum amount of shares to mint.
* @param params Deposit parameters.
* @param params.account Address of the caller of the transaction.
* @param params.token Token to deposit.
* @param params.unifiToken UniFi token to get in return of the deposit.
* @param params.amount Amount of the token to deposit.
* @param params.minimumMint Minimum amount of shares to mint.
* @param params.isPreapproved Whether the token is preapproved.
* @returns `transact: () => Promise<Address>` - Used to make the
* transaction with the given value.
*
* `estimate: () => Promise<bigint>` - Gas estimate of the
* transaction.
*/
public deposit(
walletAddress: Address,
token: Token,
amount: bigint,
minimumMint: bigint,
) {
public async deposit(params: DepositParams) {
const {
token,
unifiToken,
account,
amount,
minimumMint,
isPreapproved = false,
} = params;
const tokenAddress = TOKENS_ADDRESSES[token][this.chain];

if (isPreapproved) {
return {
transact: () =>
this.getContract().write.deposit(
[tokenAddress, amount, minimumMint],
{
account,
chain: this.viemChain,
},
),
estimate: () =>
this.getContract().estimateGas.deposit(
[tokenAddress, amount, minimumMint],
{ account },
),
};
}

const { r, s, v, deadline } = await this.erc20PermitHandler
.withToken(token)
.getPermitSignature(
account,
// The UniFi token contract is the spender.
TOKENS_ADDRESSES[unifiToken][this.chain],
amount,
);

const depositArgs = <const>[
tokenAddress,
amount,
minimumMint,
deadline,
Number(v),
r,
s,
];

const transact = () =>
this.getContract().write.deposit([tokenAddress, amount, minimumMint], {
account: walletAddress,
this.getContract().write.depositWithPermit(depositArgs, {
account,
chain: this.viemChain,
});
const estimate = () =>
this.getContract().estimateGas.deposit(
[tokenAddress, amount, minimumMint],
{
account: walletAddress,
},
);
this.getContract().estimateGas.depositWithPermit(depositArgs, {
account,
});

return { transact, estimate };
}
Expand Down
3 changes: 2 additions & 1 deletion lib/contracts/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ export const TOKENS_PERMIT_VERSION: { [key in AnyToken]: string } = {
[Token.pufETH]: '1',

// UniFi Tokens
[UnifiToken.unifiETH]: '',
// https://etherscan.io/address/0x196ead472583bc1e9af7a05f860d9857e1bd3dcc#code#F7#L172
[UnifiToken.unifiETH]: '1',
};

export const TOKENS_SALT: Partial<{
Expand Down

0 comments on commit 0be1bec

Please sign in to comment.