Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SendProvider #2078

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open

feat: SendProvider #2078

wants to merge 23 commits into from

Conversation

brendan-defi
Copy link
Contributor

@brendan-defi brendan-defi commented Mar 4, 2025

What changed? Why?

  • implemented SendProvider
  • implemented usePriceQuote hook for getPriceQuote
  • improved useExchangeRate by using usePriceHook
  • refactored prerequisite components to use context instead of props

Notes to reviewers

How has it been tested?

  • test coverage

Copy link

vercel bot commented Mar 4, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
onchainkit-coverage ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 6, 2025 7:06am
onchainkit-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 6, 2025 7:06am
onchainkit-routes ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 6, 2025 7:06am

// AmountInputTypeSwitch uses a skeleton for both loading and error states
// SendAmountInputTypeSwitch uses skeleton for the loading display
// SendAmountInputTypeSwitch uses a custom error display (see loadingDisplay default)
// SendAmountInputTypeSwitch uses skeleton for the loading display but a custom error display (see loadingDisplay default)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error state is called loadingDisplay?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should let exchangeRateLoading be handled by AmountInputTypeSwitch and just return early if there's an error - any reason we can't do that @brendan-defi?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alessey Yes, right now AmountInputTypeSwitch shows "loadingDisplay" for both loading state and exchange-rate-not-present state:

image

Copy link
Contributor Author

@brendan-defi brendan-defi Mar 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dschlabach I think I've taken that approach now, let me know what you think

},
});
}
setIsInitialized(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be derived?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, good call, this is only based on eth balance right now. refactored in 0cc4028


const tokenSymbol = selectedToken.symbol;
const tokenAddress = selectedToken.address;
let tokenParam: PriceQuoteToken;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const tokenParam = selectedToken.symbol === 'ETH' ? 'ETH' : selectedToken.address; if (tokenParam) useExchangeRate()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

statusName: 'amountChange',
statusData: {
isMissingRequiredField: true,
sufficientBalance:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasSufficientBalance? may want to hoist this calculation to the top of this function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hoisted to the top in a memo

@@ -21,7 +26,7 @@ export type SendContextType = {

// Sender Context
/** The balance of the sender's ETH wallet */
ethBalance: number | undefined;
ethBalance: number;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this have an undefined state to differentiate fetched and 0 from haven't fetched?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, now that we are using this as the derivation scheme, we need an undefined option. updated in 0cc4028

Comment on lines 12 to 16
loadingDisplay = (
<div className={cn(text.caption, color.foregroundMuted, 'h-[1.625rem]')}>
Exchange rate unavailable
</div>
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using the tags directly as default props will cause React to re-instantiate them on every render so yhou should probably extract this out to a cmponent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated how we handle error state

Comment on lines +32 to +34
if (errorDisplay) {
return errorDisplay;
}
Copy link
Contributor

@cpcramer cpcramer Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can check for this and return earlier in the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure i understand. the only thing earlier is an earlier return for loading state:
image

Comment on lines +10 to +16
classNames?: {
container?: string;
tokenName?: string;
tokenValue?: string;
fiatValue?: string;
action?: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like all of these classes are applied in the same element. Is it necessary to separate them in the prop definition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the alternative would be containerClassnames, tokenNameClassnames, etc. right?

i thought the preferred structure for multiple classNames props was an object like this.

cpcramer
cpcramer previously approved these changes Mar 6, 2025
...queryOptions,
};

const queryKey = ['getPriceQuote', token];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, don't need to define a variable here just use it in the hook

const [cryptoAmount, setCryptoAmount] = useState<string | null>(null);

// state for transaction data
const [callData, setCallData] = useState<Call | null>(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - calldata is the solidity world so we should just do calldata, setCalldata

Comment on lines +256 to +258
useEffect(() => {
fetchTransactionData();
}, [fetchTransactionData]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should move this into an internal util hook that uses React Query:

  1. It'll improve readability by moving fetching logic into its own module
  2. It'll be easier to handle things like refetching, cache management in case we ever need to tweak those parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense. does this hook belong in src/transaction?

Comment on lines +93 to +117
useEffect(() => {
const ethBalance = tokenBalances?.find((token) => token.address === '');
if (!ethBalance || ethBalance.cryptoBalance === 0) {
setEthBalance(0);
updateLifecycleStatus({
statusName: 'fundingWallet',
statusData: {
isMissingRequiredField: true,
},
});
return;
}

setEthBalance(
Number(
formatUnits(BigInt(ethBalance.cryptoBalance), ethBalance.decimals),
),
);
updateLifecycleStatus({
statusName: 'selectingAddress',
statusData: {
isMissingRequiredField: true,
},
});
}, [tokenBalances, updateLifecycleStatus]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like ethBalance could be derived state (it doesn't feel like it should be a side effect of tokenBalances loading in).

I wasn't sure what you were doing with the lifecycle statuses here but maybe there's a way to move them somewhere else where it's not a side effect of tokenBalances either?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

4 participants