diff --git a/android/app/build.gradle b/android/app/build.gradle index 1f55a5a1..8a8948f1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.mutinywallet.mutinywallet" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 48 - versionName "0.5.7" + versionCode 49 + versionName "0.5.8" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/e2e/fedimint.spec.ts b/e2e/fedimint.spec.ts index 575054fa..6ba9d244 100644 --- a/e2e/fedimint.spec.ts +++ b/e2e/fedimint.spec.ts @@ -118,7 +118,7 @@ test("fedmint join, receive, send", async ({ page }) => { await expect( page .locator("div") - .filter({ hasText: /^100 SATS$/ }) + .filter({ hasText: /^100 eSATS$/ }) .nth(1) ).toBeVisible(); diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 77a7daf1..0337b0fb 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.5.7; + MARKETING_VERSION = 1.5.8; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.mutinywallet.mutiny; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -387,7 +387,7 @@ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.5.7; + MARKETING_VERSION = 1.5.8; PRODUCT_BUNDLE_IDENTIFIER = com.mutinywallet.mutiny; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/ios/App/Gemfile.lock b/ios/App/Gemfile.lock index 7520d712..5badb11c 100644 --- a/ios/App/Gemfile.lock +++ b/ios/App/Gemfile.lock @@ -3,25 +3,25 @@ GEM specs: CFPropertyList (3.0.6) rexml - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.843.0) - aws-sdk-core (3.185.2) - aws-eventstream (~> 1, >= 1.0.2) + aws-eventstream (1.3.0) + aws-partitions (1.884.0) + aws-sdk-core (3.191.0) + aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.72.0) - aws-sdk-core (~> 3, >= 3.184.0) + aws-sdk-kms (1.77.0) + aws-sdk-core (~> 3, >= 3.191.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.136.0) - aws-sdk-core (~> 3, >= 3.181.0) + aws-sdk-s3 (1.143.0) + aws-sdk-core (~> 3, >= 3.191.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.1) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -32,11 +32,10 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.104.0) + excon (0.109.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -65,8 +64,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.7) - fastlane (2.216.0) + fastimage (2.3.0) + fastlane (2.219.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -85,6 +84,7 @@ GEM gh_inspector (>= 1.1.2, < 2.0.0) google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) google-cloud-storage (~> 1.31) highline (~> 2.0) http-cookie (~> 1.0.5) @@ -93,7 +93,7 @@ GEM mini_magick (>= 4.9.4, < 5.0.0) multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) - optparse (~> 0.1.1) + optparse (>= 0.1.1) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) security (= 0.1.3) @@ -107,9 +107,9 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.51.0) + google-apis-androidpublisher_v3 (0.54.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.2) + google-apis-core (0.11.3) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -117,24 +117,23 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml - webrick google-apis-iamcredentials_v1 (0.17.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.6.1) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.44.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -149,7 +148,7 @@ GEM domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.2) - json (2.6.3) + json (2.7.1) jwt (2.7.1) mini_magick (4.12.0) mini_mime (1.1.5) @@ -157,10 +156,10 @@ GEM multipart-post (2.3.0) nanaimo (0.3.0) naturally (2.2.1) - optparse (0.1.1) + optparse (0.4.0) os (1.1.4) - plist (3.7.0) - public_suffix (5.0.3) + plist (3.7.1) + public_suffix (5.0.4) rake (13.1.0) representable (3.2.0) declarative (< 0.1.0) @@ -185,17 +184,13 @@ GEM unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) - tty-screen (0.8.1) + tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) unicode-display_width (2.5.0) - webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.23.0) + xcodeproj (1.24.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) diff --git a/package.json b/package.json index 8a708c44..52fbf3fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mutiny-wallet", - "version": "0.5.7", + "version": "0.5.8", "license": "MIT", "packageManager": "pnpm@8.6.6", "scripts": { @@ -55,7 +55,7 @@ "@kobalte/core": "^0.9.8", "@kobalte/tailwindcss": "^0.5.0", "@modular-forms/solid": "^0.18.1", - "@mutinywallet/mutiny-wasm": "0.5.7", + "@mutinywallet/mutiny-wasm": "0.5.8", "@mutinywallet/waila-wasm": "^0.2.6", "@solid-primitives/upload": "^0.0.111", "@solidjs/meta": "^0.29.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 56ad47bc..1093e522 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,8 +54,8 @@ importers: specifier: ^0.18.1 version: 0.18.1(solid-js@1.8.5) '@mutinywallet/mutiny-wasm': - specifier: 0.5.7 - version: 0.5.7 + specifier: 0.5.8 + version: 0.5.8 '@mutinywallet/waila-wasm': specifier: ^0.2.6 version: 0.2.6 @@ -2570,8 +2570,8 @@ packages: solid-js: 1.8.5 dev: false - /@mutinywallet/mutiny-wasm@0.5.7: - resolution: {integrity: sha512-swz7lFC86b8zWAc5gDz4I4O+66va2aOS9sHOkKhG0SEMp2vVti11Y4lpN0aJVuCy8Wx4FNZZLSxro00pYyf8kQ==} + /@mutinywallet/mutiny-wasm@0.5.8: + resolution: {integrity: sha512-Bwx3sMXuMiE876Kk1FI9uZoJMPkHc5RGFmUHsFeSMMGDxC2YLO5N5ilaIIig89ZbAYcBi7Y1N4Nq/2nZFcM+9A==} dev: false /@mutinywallet/waila-wasm@0.2.6: diff --git a/src/assets/icons/private-eye.svg b/src/assets/icons/private-eye.svg new file mode 100644 index 00000000..3d63610e --- /dev/null +++ b/src/assets/icons/private-eye.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/components/Amount.tsx b/src/components/Amount.tsx index 4e28499a..df2c01a6 100644 --- a/src/components/Amount.tsx +++ b/src/components/Amount.tsx @@ -18,6 +18,7 @@ export function AmountSats(props: { amountSats: bigint | number | undefined; icon?: "lightning" | "community" | "chain" | "plus" | "minus"; denominationSize?: "sm" | "lg" | "xl"; + isFederation?: boolean; }) { const i18n = useI18n(); return ( @@ -54,14 +55,18 @@ export function AmountSats(props: { Number(props.amountSats) === 0 } > - {i18n.t("common.sats")} + {props.isFederation + ? i18n.t("common.e_sats") + : i18n.t("common.sats")} - {i18n.t("common.sat")} + {props.isFederation + ? i18n.t("common.e_sat") + : i18n.t("common.sat")} diff --git a/src/components/AmountEditable.tsx b/src/components/AmountEditable.tsx index a029ead1..2ea426d8 100644 --- a/src/components/AmountEditable.tsx +++ b/src/components/AmountEditable.tsx @@ -7,7 +7,7 @@ import { Show } from "solid-js"; -import { AmountSats, BigMoney } from "~/components"; +import { AmountSats, BigMoney, SharpButton } from "~/components"; import { useMegaStore } from "~/state/megaStore"; import { btcFloatRounding, @@ -106,7 +106,6 @@ export const AmountEditable: ParentComponent<{ ); } } else { - console.log("we're in the fiat branch"); sane = fiatInputSanitizer( value.replace(",", "."), state.fiat.maxFractionalDigits @@ -270,20 +269,17 @@ function MethodChooser(props: { props.setChosenMethod && props.setChosenMethod(nextMethod); } return ( - + <> + + + + ); } diff --git a/src/components/BalanceBox.tsx b/src/components/BalanceBox.tsx index 40821db5..f1755f28 100644 --- a/src/components/BalanceBox.tsx +++ b/src/components/BalanceBox.tsx @@ -94,20 +94,38 @@ export function BalanceBox(props: { loading?: boolean }) { }>
-
-
- -
-
- +
+
+
+ +
+
+ +
+ 0n}> +
+ + swaplightning + +
+
diff --git a/src/components/BigMoney.tsx b/src/components/BigMoney.tsx index 956efd5a..08987618 100644 --- a/src/components/BigMoney.tsx +++ b/src/components/BigMoney.tsx @@ -103,7 +103,7 @@ export function BigMoney(props: {
diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx index 06548841..b06fc9af 100644 --- a/src/components/ContactForm.tsx +++ b/src/components/ContactForm.tsx @@ -38,7 +38,7 @@ export function ContactForm(props: { return (
diff --git a/src/components/ContactViewer.tsx b/src/components/ContactViewer.tsx index 92536137..cf33afb4 100644 --- a/src/components/ContactViewer.tsx +++ b/src/components/ContactViewer.tsx @@ -5,6 +5,7 @@ import { createSignal, Match, Show, Switch } from "solid-js"; import { Button, + ConfirmDialog, ContactForm, KeyValue, MiniStringShower, @@ -27,12 +28,14 @@ export function ContactViewer(props: { contact: TagItem; gradient: string; saveContact: (id: string, contact: ContactFormValues) => void; + deleteContact: (id: string) => Promise; }) { const i18n = useI18n(); const [isOpen, setIsOpen] = createSignal(false); const [isEditing, setIsEditing] = createSignal(false); const [state, actions] = useMegaStore(); const navigate = useNavigate(); + const [confirmOpen, setConfirmOpen] = createSignal(false); const handleSubmit: SubmitHandler = ( c: ContactFormValues @@ -43,6 +46,13 @@ export function ContactViewer(props: { setIsEditing(false); }; + const handleDelete = async () => { + const id = props.contact.id; + + await props.deleteContact(id); + setIsOpen(false); + }; + const handlePay = () => { const network = state.mutiny_wallet?.get_network() || "signet"; @@ -101,6 +111,20 @@ export function ContactViewer(props: { handleSubmit={handleSubmit} initialValues={props.contact} /> + + setConfirmOpen(false)} + > + Are you sure you want to delete this contact? +
diff --git a/src/components/Failure.tsx b/src/components/Failure.tsx new file mode 100644 index 00000000..6aefbbf9 --- /dev/null +++ b/src/components/Failure.tsx @@ -0,0 +1,41 @@ +import { A } from "@solidjs/router"; +import { Match, Switch } from "solid-js"; + +import { InfoBox, MegaClock, MegaEx } from "~/components"; +import { useI18n } from "~/i18n/context"; + +export function Failure(props: { reason: string }) { + const i18n = useI18n(); + + return ( + + + +

+ {i18n.t("send.payment_pending")} +

+ + {i18n.t("send.payment_pending_description")} + +
+ + +

+ {i18n.t("send.error_channel_reserves")} +

+ + {i18n.t("send.error_channel_reserves_explained")}{" "} + {i18n.t("common.why")} + +
+ + +

+ {props.reason} +

+
+
+ ); +} diff --git a/src/components/ReceiveWarnings.tsx b/src/components/ReceiveWarnings.tsx index 13564623..aa4d2dd1 100644 --- a/src/components/ReceiveWarnings.tsx +++ b/src/components/ReceiveWarnings.tsx @@ -5,7 +5,10 @@ import { FeesModal } from "~/components/MoreInfoModal"; import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; -export function ReceiveWarnings(props: { amountSats: string | bigint }) { +export function ReceiveWarnings(props: { + amountSats: string | bigint; + from_fedi_to_ln: boolean; +}) { const i18n = useI18n(); const [state, _actions] = useMegaStore(); @@ -26,7 +29,7 @@ export function ReceiveWarnings(props: { amountSats: string | bigint }) { }); const warningText = () => { - if (state.federations?.length !== 0) { + if (state.federations?.length !== 0 && props.from_fedi_to_ln != true) { return undefined; } if ((state.balance?.lightning || 0n) === 0n) { diff --git a/src/components/SharpButton.tsx b/src/components/SharpButton.tsx new file mode 100644 index 00000000..b17da582 --- /dev/null +++ b/src/components/SharpButton.tsx @@ -0,0 +1,21 @@ +import { JSX } from "solid-js"; + +export function SharpButton(props: { + onClick: () => void; + children: JSX.Element; + disabled?: boolean; +}) { + return ( + + ); +} diff --git a/src/components/index.ts b/src/components/index.ts index 241728ba..3b6a779f 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -36,6 +36,7 @@ export * from "./Restart"; export * from "./ResyncOnchain"; export * from "./SeedWords"; export * from "./SetupErrorDisplay"; +export * from "./Failure"; export * from "./ShareCard"; export * from "./Toaster"; export * from "./NostrActivity"; @@ -50,3 +51,4 @@ export * from "./FeeDisplay"; export * from "./ReceiveWarnings"; export * from "./SimpleInput"; export * from "./LabelCircle"; +export * from "./SharpButton"; diff --git a/src/i18n/en/translations.ts b/src/i18n/en/translations.ts index 120f9e8f..44463015 100644 --- a/src/i18n/en/translations.ts +++ b/src/i18n/en/translations.ts @@ -3,6 +3,8 @@ export default { title: "Mutiny Wallet", nice: "Nice", home: "Home", + e_sats: "eSATS", + e_sat: "eSAT", sats: "SATS", sat: "SAT", fee: "Fee", @@ -126,6 +128,7 @@ export default { sats_sent: "sats sent" }, what_for: "What's this for?", + zap_note: "Zap note", error_low_balance: "We do not have enough balance to pay the given amount.", error_invoice_match: @@ -144,7 +147,9 @@ export default { payment_pending_description: "It's taking a while, but it's possible this payment may still go through. Please check 'Activity' for the current status.", hodl_invoice_warning: - "This is a hodl invoice. Payments to hodl invoices can cause channel force closes, which results in high on-chain fees. Pay at your own risk!" + "This is a hodl invoice. Payments to hodl invoices can cause channel force closes, which results in high on-chain fees. Pay at your own risk!", + private: "Private", + anonzap: "Anon Zap" }, feedback: { header: "Give us feedback!", @@ -595,6 +600,19 @@ export default { connecting: "Connecting...", confirm_swap: "Confirm Swap" }, + swap_lightning: { + insufficient_funds: "You don't have enough funds to swap to lightning", + header: "Swap to Lightning", + header_preview: "Preview Swap", + completed: "Swap Completed", + too_small: + "Invalid amount entered. You need to swap at least 100k sats.", + sats_added: + "+{{amount}} sats have been added to your Lightning balance", + sats_fee: "+{{amount}} sats fee", + confirm_swap: "Confirm Swap", + preview_swap: "Preview Swap Fee" + }, reload: { mutiny_update: "Mutiny Update", new_version_description: diff --git a/src/router.tsx b/src/router.tsx index 8eea78a7..557331ee 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -15,7 +15,8 @@ import { Scanner, Search, Send, - Swap + Swap, + SwapLightning } from "~/routes"; import { Admin, @@ -101,6 +102,7 @@ export function Router() { + diff --git a/src/routes/Activity.tsx b/src/routes/Activity.tsx index 773649bf..04ae3da0 100644 --- a/src/routes/Activity.tsx +++ b/src/routes/Activity.tsx @@ -71,7 +71,6 @@ function ContactRow() { refetch(); } - // async function saveContact(id: string, contact: ContactFormValues) { console.log("saving contact", id, contact); const hexpub = await hexpubFromNpub(contact.npub?.trim()); @@ -95,6 +94,16 @@ function ContactRow() { refetch(); } + async function deleteContact(id: string) { + try { + await state.mutiny_wallet?.delete_contact(id); + } catch (e) { + console.error(e); + showToast(eify(e)); + } + refetch(); + } + return (
@@ -106,6 +115,7 @@ function ContactRow() { contact={contact} gradient={gradients()?.get(contact.name)} saveContact={saveContact} + deleteContact={deleteContact} /> )} diff --git a/src/routes/Receive.tsx b/src/routes/Receive.tsx index 51360623..6a347fb3 100644 --- a/src/routes/Receive.tsx +++ b/src/routes/Receive.tsx @@ -377,7 +377,10 @@ export function Receive() { setAmountSats={setAmount} onSubmit={getQr} /> - +
diff --git a/src/routes/Search.tsx b/src/routes/Search.tsx index a95c1cb6..ec6cacf5 100644 --- a/src/routes/Search.tsx +++ b/src/routes/Search.tsx @@ -465,6 +465,16 @@ function ContactButton(props: { onClick: () => void; }) { const i18n = useI18n(); + + const primalUrl = createMemo(() => { + const originalUrl = props.contact.image_url; + if (!originalUrl) return undefined; + + return `https://primal.b-cdn.net/media-cache?s=s&a=1&u=${encodeURIComponent( + originalUrl + )}`; + }); + return ( + + + + + + + + + 0n} + > + + {amountWarning()} + + + +
+ + + + + +
+ + + + ); +} diff --git a/src/routes/index.ts b/src/routes/index.ts index 923dec31..a47f92d4 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -7,4 +7,5 @@ export * from "./Receive"; export * from "./Scanner"; export * from "./Send"; export * from "./Swap"; +export * from "./SwapLightning"; export * from "./Search"; diff --git a/src/routes/settings/ManageFederations.tsx b/src/routes/settings/ManageFederations.tsx index ead77b4c..e3860dea 100644 --- a/src/routes/settings/ManageFederations.tsx +++ b/src/routes/settings/ManageFederations.tsx @@ -185,6 +185,7 @@ function FederationListItem(props: {