Skip to content

Commit

Permalink
Fix approving BPT spending with Gauges
Browse files Browse the repository at this point in the history
When staking a user must allow a gauge to spend their token. However
when we check for user allowances we only check for tokens the vault
can spend, not the allowances for gauges. By allowing injecting a
spender we can inject the gauge into the spenders list which then
fetches allowances for it when then makes it able to correctly tell if
the user has allowed the gauge to spend their BPT.

This fixes the post approval check always failing when staking BPT.
  • Loading branch information
timjrobinson committed Jun 30, 2023
1 parent f1d50e6 commit 9808a6e
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 11 deletions.
11 changes: 9 additions & 2 deletions src/composables/approvals/useTokenApprovalActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ export default function useTokenApprovalActions() {
/**
* COMPOSABLES
*/
const { refetchAllowances, approvalsRequired, approvalRequired, getToken } =
useTokens();
const {
refetchAllowances,
approvalsRequired,
approvalRequired,
getToken,
injectSpenders,
} = useTokens();
const { t } = useI18n();
const { getSigner } = useWeb3();
const { addTransaction } = useTransactions();
Expand Down Expand Up @@ -89,6 +94,7 @@ export default function useTokenApprovalActions() {
amountsToApprove: AmountToApprove[],
spender: string
): Promise<AmountToApprove[]> {
await injectSpenders([spender]);
await refetchAllowances();
return approvalsRequired(amountsToApprove, spender);
}
Expand All @@ -97,6 +103,7 @@ export default function useTokenApprovalActions() {
amountToApprove: AmountToApprove,
spender: string
): Promise<boolean> {
await injectSpenders([spender]);
await refetchAllowances();
return !approvalRequired(
amountToApprove.address,
Expand Down
4 changes: 2 additions & 2 deletions src/composables/queries/useAllowancesQuery.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ test('Returns token allowances from balancer SDK', async () => {

initMulticall(generateMulticallMock(processCall));

const allowanceContracts = ref([
const spenders = ref([
'0xBA12222222228d8Ba445958a75a0704d566BF2C8',
'0x6320cD32aA674d2898A68ec82e869385Fc5f7E2f',
'0x33A99Dcc4C85C014cf12626959111D5898bbCAbF',
]);

const { result } = mountComposable(() =>
useAllowancesQuery(tokens, allowanceContracts)
useAllowancesQuery(tokens, spenders)
);

const data = await waitForQueryData(result);
Expand Down
2 changes: 1 addition & 1 deletion src/providers/__mocks__/tokens.provider.fake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ silenceConsoleLog(vi, message => message.startsWith('Fetching'));
export interface TokensProviderState {
loading: boolean;
injectedTokens: TokenInfoMap;
allowanceContracts: string[];
spenders: string[];
injectedPrices: TokenPrices;
}

Expand Down
30 changes: 24 additions & 6 deletions src/providers/tokens.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const { uris: tokenListUris } = tokenListService;
export interface TokensProviderState {
loading: boolean;
injectedTokens: TokenInfoMap;
allowanceContracts: string[];
spenders: string[];
injectedPrices: TokenPrices;
}

Expand Down Expand Up @@ -87,7 +87,7 @@ export const tokensProvider = (
const state: TokensProviderState = reactive({
loading: true,
injectedTokens: {},
allowanceContracts: compact([
spenders: compact([
networkConfig.addresses.vault,
networkConfig.tokens.Addresses.wstETH,
configService.network.addresses.veBAL,
Expand Down Expand Up @@ -173,7 +173,7 @@ export const tokensProvider = (
isRefetching: allowanceQueryRefetching,
isError: allowancesQueryError,
refetch: refetchAllowances,
} = useAllowancesQuery(tokens, toRef(state, 'allowanceContracts'));
} = useAllowancesQuery(tokens, toRef(state, 'spenders'));

const prices = computed(
(): TokenPrices => (priceData.value ? priceData.value : {})
Expand Down Expand Up @@ -278,6 +278,21 @@ export const tokensProvider = (
await forChange(onchainDataLoading, false);
}

/**
* Injects contract addresses that could possibly spend the users tokens into
* the spenders map. E.g. This is used for injecting gauges into the map as they
* must be allowed to spend a users BPT in order to stake the BPT in the gauge.
*/
async function injectSpenders(addresses: string[]): Promise<void> {
addresses = addresses.filter(a => a).map(getAddress);

state.spenders = [...new Set(state.spenders.concat(addresses))];

// Wait for balances/allowances to be fetched for newly injected tokens.
await nextTick();
await forChange(onchainDataLoading, false);
}

/**
* Given query, filters tokens map by name, symbol or address.
* If address is provided, search for address in tokens or injectToken
Expand Down Expand Up @@ -344,14 +359,16 @@ export const tokensProvider = (
function approvalRequired(
tokenAddress: string,
amount: string,
contractAddress = networkConfig.addresses.vault
spenderAddress = networkConfig.addresses.vault
): boolean {
if (!amount || bnum(amount).eq(0)) return false;
if (!contractAddress) return false;
if (!spenderAddress) return false;
if (isSameAddress(tokenAddress, nativeAsset.address)) return false;

const allowance = bnum(
(allowances.value[contractAddress] || {})[getAddress(tokenAddress)]
(allowances.value[getAddress(spenderAddress)] || {})[
getAddress(tokenAddress)
]
);
return allowance.lt(amount);
}
Expand Down Expand Up @@ -510,6 +527,7 @@ export const tokensProvider = (
refetchBalances,
refetchAllowances,
injectTokens,
injectSpenders,
searchTokens,
hasBalance,
approvalRequired,
Expand Down

0 comments on commit 9808a6e

Please sign in to comment.