-
Notifications
You must be signed in to change notification settings - Fork 29
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
enable sending a token or a SAC payment to a C address #1424
Changes from 1 commit
927a301
ea0172b
5bdbe36
97bd10b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,13 @@ import { useSelector, useDispatch } from "react-redux"; | |
import { Formik, Form, Field, FieldProps } from "formik"; | ||
import { Icon, Textarea, Link, Button } from "@stellar/design-system"; | ||
import { useTranslation } from "react-i18next"; | ||
import { Asset } from "stellar-sdk"; | ||
|
||
import { navigateTo } from "popup/helpers/navigate"; | ||
import { useNetworkFees } from "popup/helpers/useNetworkFees"; | ||
import { useIsSwap } from "popup/helpers/useIsSwap"; | ||
import { isMuxedAccount } from "helpers/stellar"; | ||
import { getNativeContractDetails } from "popup/helpers/searchAsset"; | ||
import { isMuxedAccount, getAssetFromCanonical } from "helpers/stellar"; | ||
import { ROUTES } from "popup/constants/routes"; | ||
import { SubviewHeader } from "popup/components/SubviewHeader"; | ||
import { FormRows } from "popup/basics/Forms"; | ||
|
@@ -19,13 +21,14 @@ import { | |
saveTransactionFee, | ||
saveSimulation, | ||
transactionSubmissionSelector, | ||
saveIsToken, | ||
} from "popup/ducks/transactionSubmission"; | ||
import { simulateTokenPayment, simulateSwap } from "popup/ducks/token-payment"; | ||
|
||
import { InfoTooltip } from "popup/basics/InfoTooltip"; | ||
import { publicKeySelector } from "popup/ducks/accountServices"; | ||
import { settingsNetworkDetailsSelector } from "popup/ducks/settings"; | ||
import { parseTokenAmount } from "popup/helpers/soroban"; | ||
import { parseTokenAmount, isContractId } from "popup/helpers/soroban"; | ||
import { Balances, TokenBalance } from "@shared/api/types"; | ||
import { AppDispatch } from "popup/App"; | ||
|
||
|
@@ -85,6 +88,24 @@ export const Settings = ({ | |
// dont show memo for regular sends to Muxed, or for swaps | ||
const showMemo = !isSwap && !isMuxedAccount(destination); | ||
const showSlippage = (isPathPayment || isSwap) && !isSoroswap; | ||
const isSendSacToContract = | ||
isContractId(destination) && | ||
!isContractId(getAssetFromCanonical(asset).issuer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic here is basically: |
||
const getSacContractAddress = () => { | ||
if (asset === "native") { | ||
return getNativeContractDetails(networkDetails).contract; | ||
} | ||
|
||
const assetFromCanonical = new Asset( | ||
getAssetFromCanonical(asset).code, | ||
getAssetFromCanonical(asset).issuer, | ||
); | ||
const contractAddress = assetFromCanonical.contractId( | ||
networkDetails.networkPassphrase, | ||
); | ||
|
||
return contractAddress; | ||
}; | ||
|
||
async function goToReview() { | ||
if (isSoroswap) { | ||
|
@@ -109,8 +130,10 @@ export const Settings = ({ | |
return; | ||
} | ||
|
||
if (isToken) { | ||
const assetAddress = asset.split(":")[1]; | ||
if (isToken || isSendSacToContract) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sending a token to a C address generally worked "out of the box" once I allowed a user to enter a C address as a destination 🎉 |
||
const assetAddress = isSendSacToContract | ||
? getSacContractAddress() | ||
: asset.split(":")[1]; | ||
const balances = | ||
accountBalances.balances || ({} as NonNullable<Balances>); | ||
const assetBalance = balances[asset] as TokenBalance; | ||
|
@@ -119,10 +142,9 @@ export const Settings = ({ | |
throw new Error("Asset Balance not available"); | ||
} | ||
|
||
const parsedAmount = parseTokenAmount( | ||
amount, | ||
Number(assetBalance.decimals), | ||
); | ||
const parsedAmount = isSendSacToContract | ||
? parseTokenAmount(amount, 7) | ||
: parseTokenAmount(amount, Number(assetBalance.decimals)); | ||
|
||
const params = { | ||
publicKey, | ||
|
@@ -143,6 +165,7 @@ export const Settings = ({ | |
|
||
if (simulateTokenPayment.fulfilled.match(simulation)) { | ||
dispatch(saveSimulation(simulation.payload)); | ||
dispatch(saveIsToken(true)); | ||
navigateTo(next); | ||
} | ||
return; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ import { IdenticonImg } from "popup/components/identicons/IdenticonImg"; | |
import { FormRows } from "popup/basics/Forms"; | ||
import { emitMetric } from "helpers/metrics"; | ||
import { navigateTo } from "popup/helpers/navigate"; | ||
import { isContractId } from "popup/helpers/soroban"; | ||
import { METRIC_NAMES } from "popup/constants/metricsNames"; | ||
import { ROUTES } from "popup/constants/routes"; | ||
import { View } from "popup/basics/layout/View"; | ||
|
@@ -88,7 +89,7 @@ const InvalidAddressWarning = () => { | |
icon={<Icon.Warning />} | ||
title={t("INVALID STELLAR ADDRESS")} | ||
> | ||
{t("Addresses are uppercase and begin with letters “G“ or “M“.")} | ||
{t("Addresses are uppercase and begin with letters “G“, “M“, or “C“.")} | ||
</Notification> | ||
</div> | ||
); | ||
|
@@ -106,7 +107,7 @@ export const SendTo = ({ previous }: { previous: ROUTES }) => { | |
); | ||
|
||
const [recentAddresses, setRecentAddresses] = useState<string[]>([]); | ||
const [validatedPubKey, setValidatedPubKey] = useState(""); | ||
const [validatedAddress, setValidatedAddress] = useState(""); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. var rename to reflect we can send to either a public key or a C address |
||
const [fedAddress, setFedAddress] = useState(""); | ||
const [isLoading, setIsLoading] = useState(false); | ||
|
||
|
@@ -122,14 +123,17 @@ export const SendTo = ({ previous }: { previous: ROUTES }) => { | |
const formik = useFormik({ | ||
initialValues: { destination: federationAddress || destination }, | ||
onSubmit: () => { | ||
handleContinue(validatedPubKey, fedAddress); | ||
handleContinue(validatedAddress, fedAddress); | ||
}, | ||
validateOnChange: false, | ||
validate: (values) => { | ||
if (isValidPublicKey(values.destination)) { | ||
if ( | ||
isValidPublicKey(values.destination) || | ||
isContractId(values.destination) | ||
) { | ||
return {}; | ||
} | ||
return { destination: t("invalid public key") }; | ||
return { destination: t("invalid destination address") }; | ||
}, | ||
}); | ||
|
||
|
@@ -157,19 +161,19 @@ export const SendTo = ({ previous }: { previous: ROUTES }) => { | |
} | ||
// muxed account | ||
if (isMuxedAccount(inputDest)) { | ||
setValidatedPubKey(inputDest); | ||
setValidatedAddress(inputDest); | ||
} else if (isFederationAddress(inputDest)) { | ||
// federation address | ||
try { | ||
const fedResp = await Federation.Server.resolve(inputDest); | ||
setValidatedPubKey(fedResp.account_id); | ||
setValidatedAddress(fedResp.account_id); | ||
setFedAddress(inputDest); | ||
} catch (e) { | ||
formik.setErrors({ destination: t("invalid federation address") }); | ||
} | ||
} else { | ||
// else, a regular account | ||
setValidatedPubKey(inputDest); | ||
setValidatedAddress(inputDest); | ||
} | ||
setIsLoading(false); | ||
}, 2000), | ||
|
@@ -192,30 +196,35 @@ export const SendTo = ({ previous }: { previous: ROUTES }) => { | |
setIsLoading(true); | ||
} | ||
// reset | ||
setValidatedPubKey(""); | ||
setValidatedAddress(""); | ||
setFedAddress(""); | ||
db(formik.values.destination); | ||
}, [db, formik.values.destination]); | ||
|
||
// on valid input get destination balances | ||
useEffect(() => { | ||
if (!validatedPubKey) { | ||
if (!validatedAddress) { | ||
return; | ||
} | ||
|
||
// TODO - remove once wallet-sdk can handle muxed | ||
let publicKey = validatedPubKey; | ||
if (isMuxedAccount(validatedPubKey)) { | ||
const mAccount = MuxedAccount.fromAddress(validatedPubKey, "0"); | ||
publicKey = mAccount.baseAccount().accountId(); | ||
let address = validatedAddress; | ||
|
||
if (isContractId(validatedAddress)) { | ||
return; | ||
} | ||
|
||
if (isMuxedAccount(validatedAddress)) { | ||
const mAccount = MuxedAccount.fromAddress(validatedAddress, "0"); | ||
address = mAccount.baseAccount().accountId(); | ||
} | ||
dispatch( | ||
getDestinationBalances({ | ||
publicKey, | ||
publicKey: address, | ||
networkDetails, | ||
}), | ||
); | ||
}, [dispatch, validatedPubKey, networkDetails]); | ||
}, [dispatch, validatedAddress, networkDetails]); | ||
|
||
return ( | ||
<React.Fragment> | ||
|
@@ -262,10 +271,10 @@ export const SendTo = ({ previous }: { previous: ROUTES }) => { | |
address, | ||
); | ||
const publicKey = fedResp.account_id; | ||
setValidatedPubKey(publicKey); | ||
setValidatedAddress(publicKey); | ||
handleContinue(publicKey, address); | ||
} else { | ||
setValidatedPubKey(address); | ||
setValidatedAddress(address); | ||
handleContinue(address); | ||
} | ||
}} | ||
|
@@ -305,8 +314,8 @@ export const SendTo = ({ previous }: { previous: ROUTES }) => { | |
)} | ||
<div className="SendTo__subheading">Address</div> | ||
<div className="SendTo__subheading-identicon"> | ||
<IdenticonImg publicKey={validatedPubKey} /> | ||
<span>{truncatedPublicKey(validatedPubKey)}</span> | ||
<IdenticonImg publicKey={validatedAddress} /> | ||
<span>{truncatedPublicKey(validatedAddress)}</span> | ||
</div> | ||
</> | ||
) : null} | ||
|
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 just a var name issue that was bugging me , so fixing it here