-
Notifications
You must be signed in to change notification settings - Fork 375
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
Add fee estimation for Withdrawing CELO and pay for Withdrawing and Selling CELO fees in CELO #5345
Conversation
|
||
type Props = StackScreenProps<StackParamList, Screens.WithdrawCeloScreen> | ||
|
||
const RANDOM_ADDRESS = '0xDCE9762d6C1fe89FF4f3857832131Ca18eE15C66' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have an address here yet to do the estimation, and estimating requires an address, so I used a random one. Could that cause any issues?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, we already do this here as well.
// TODO: Make it transparent for the user. | ||
// TODO: Check for balance should be more than fee instead of zero. | ||
const feeCurrency = | ||
preferredFeeCurrency === CURRENCY_ENUM.DOLLAR && stableTokenBalance.isGreaterThan(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was working like this before and I was worried about changing it in case someone only has CELO and needs to pay for gas for something, but I would understand not wanting to have it anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this create a potential discrepancy between what we show users and what we actually do? For example, if someone has both cUSD and CELO, we will always show them the fee in CELO but then will always deduct their fee from their cUSD balance.
If my understanding is correct, I think we need to get rid of this. It looks like you've set the default currency = cUSD for the param in the relevant function calls but I'd definitely test it out to be safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, I totally misread this the first time. Sounds good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! 👍
const feeCurrencyAddress = | ||
feeCurrency === CURRENCY_ENUM.DOLLAR | ||
? yield call(getCurrencyAddress, CURRENCY_ENUM.DOLLAR) | ||
: undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Would be nice to add a small comment explaining it's normal that we pass undefined
when the feeCurrency
is CELO
.
useEffect(() => { | ||
getSendFee( | ||
accountAddress, | ||
CURRENCY_ENUM.GOLD, | ||
{ | ||
recipientAddress: RANDOM_ADDRESS, | ||
amount: goldBalanceNumber, | ||
comment: '', | ||
}, | ||
false | ||
) | ||
.then((estimate: BigNumber) => { | ||
setFeeEstimate(divideByWei(estimate)) | ||
}) | ||
.catch((error) => { | ||
Logger.warn('WithdrawCeloScreen', `Error found while estimating gas fee: ${error}`) | ||
}) | ||
}, []) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Async functions should be avoided in general in useEffect
because they can trigger actions after the component has been unmounted.
useAsync
from react-async-hook solves this.
Now we have CalculateFee which uses useAsync
under the hood and mostly does what you want here.
I originally created it as a component because most components we had at the time, were class components.
But we could export a useSendFee
hook from it now.
Added benefit is it provides loading/error states so we can display a spinner while it's calculating and it displays an error if it fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! I had run into this many times and always solved it in this inelegant way, the useAsync
hook looks great.
|
||
type Props = StackScreenProps<StackParamList, Screens.WithdrawCeloScreen> | ||
|
||
const RANDOM_ADDRESS = '0xDCE9762d6C1fe89FF4f3857832131Ca18eE15C66' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, we already do this here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the parts that I am familiar with look good. I am less familiar with the react native components, so I am going to defer to @jeanregisser for final approval.
@@ -14,6 +14,7 @@ const SAMPLE_AMOUNT = new BigNumber(5.001) | |||
const mockScreenProps = getMockStackScreenProps(Screens.WithdrawCeloReviewScreen, { | |||
recipientAddress: SAMPLE_ADDRESS, | |||
amount: SAMPLE_AMOUNT, | |||
feeEstimate: new BigNumber(1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this 1 wei, and if so, is that displayed to the user at all? If the fee was actually 1 wei, it would likely not be significant enough to warrant mentioning (unless they are trying to withdraw 100% of their balance, in which case we might help craft a request that won't leave any dust behind.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing! The wei to CELO mapping happens in WithdrawCeloScreen
, line 67. The converted fee is then passed to this review screen and this is a test of it where I put a != 0 number just to have something there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! One comment I think needs to be addressed
function WithdrawCeloScreen({ navigation }: Props) { | ||
const [accountAddress, setAccountAddress] = useState('') | ||
const [celoInput, setCeloToTransfer] = useState('') | ||
|
||
const goldBalance = useSelector((state) => state.goldToken.balance) | ||
const goldBalanceNumber = new BigNumber(goldBalance || 0) | ||
const goldBalanceNumber = useMemo(() => new BigNumber(goldBalance || 0), [goldBalance]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use useMemo
here?
My understanding for the best use cases of this is for when there are expensive calculations involved, otherwise the storage costs are not worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, great catch, I'd like not to have it either, the problem is that we're creating a new BigNumber
instance on each render and we pass this to the useSendFee
hook, which uses it to see whether dependencies changed or not. If we pass different instances it assumes it changed and re-calculates the fee, which is undesired. The useMemo
caches the instance of BigNumber
so we use always the same unless the total balance changes for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's an interesting problem and a creative solution.
I don't feel strongly about doing this now but an alternative is to pass an int
value instead and convert to BigNumber
within the useSendFee
function. If this would require a bunch of other changes, I'd understand if you'd rather not do it. But if that's the case, please leave a "to-do" so we fix this later.
As a side note, do you think we are having this issue in other places we are doing fee estimates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this comment somehow. I changed the amount
to a string
since I saw it was being transformed to string right after anyways.
I checked the other places but didn't find something like this happening
// TODO: Make it transparent for the user. | ||
// TODO: Check for balance should be more than fee instead of zero. | ||
const feeCurrency = | ||
preferredFeeCurrency === CURRENCY_ENUM.DOLLAR && stableTokenBalance.isGreaterThan(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this create a potential discrepancy between what we show users and what we actually do? For example, if someone has both cUSD and CELO, we will always show them the fee in CELO but then will always deduct their fee from their cUSD balance.
If my understanding is correct, I think we need to get rid of this. It looks like you've set the default currency = cUSD for the param in the relevant function calls but I'd definitely test it out to be safe.
Before this change we used cUSD if there was enough balance and CELO otherwise. The new parameter The condition is to maintain the logic we used to have for all other cases (where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! 👍
</TextInputWithButtons> | ||
) | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
maxAmount: fontStyles.small600, | ||
loadingContainer: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadingContainer: {}, |
Hi @jeanregisser , @gnardini Verified task using latest Test flight build v1.4.0 (28) and Android play store (internal build) v1.4.0 (1004294317) and found the following:
Can you please let us know 3rd and 4th point are expected and Also, let us know if we need to verify anything else. Thanks!! |
All good thanks. The fee is probably rounded up for display. |
Description
Add a fee calculation for withdrawing CELO. This will be removed soonish when we do offline fee calculations (it's an epic in the upcoming milestone). This is meant as a quick fix in the meantime to not have a 0 hard-coded.
When withdrawing CELO or selling CELO. The fee is now paid for with CELO instead of cUSD.
I didn't add fee estimations for exchanging because it uses more than one transaction and made the calculation somewhat more complex, it will probably be improved doing offline estimations.
Tested
Tested it in an emulator, just looking at the estimate and paying attention to the exact CELO balance in the logs when doing different operations to see that the balance changes more than expected (meaning that gas was paid for in CELO) only when doing withdrawals and selling CELO.
Related issues