diff --git a/components/overlays/ChooseWalletOverlay.vue b/components/overlays/ChooseWalletOverlay.vue
index 1a9ac0c..bf2b322 100644
--- a/components/overlays/ChooseWalletOverlay.vue
+++ b/components/overlays/ChooseWalletOverlay.vue
@@ -76,15 +76,37 @@
+
+
+ your currently selected account is {{ accountStore.getAddress }}
+
+
+
+ Change Session Key Authorization
+
+
+
-
+
please allow this app to read your balance by signing the upcoming
request in your extension
-
this window will close once a balance could be fetched
+
+ this window will close once a balance could be fetched
+
@@ -94,15 +116,35 @@
import {
connectExtension,
extensionAccounts,
- injectorForAddress,
} from "~/lib/signerExtensionUtils";
import OverlayDialog from "~/components/overlays/OverlayDialog.vue";
-import { defineProps, computed, ref, watch } from "vue";
+import { computed, defineProps, ref, watch } from "vue";
import { useAccount } from "~/store/account.ts";
+import { encodeAddress } from "@polkadot/util-crypto";
+import { SessionProxyRole } from "~/lib/sessionProxyStorage";
const accountStore = useAccount();
+const currentExtensionAccount = ref("");
const selectedExtensionAccount = ref("");
+const selectedExtensionAccountIsNew = computed(() => {
+ try {
+ const selectedAddressEncoded = encodeAddress(
+ selectedExtensionAccount.value,
+ accountStore.getSs58Format,
+ );
+ console.log(
+ "comparing",
+ currentExtensionAccount.value,
+ " to ",
+ selectedAddressEncoded,
+ );
+ return selectedAddressEncoded !== currentExtensionAccount.value;
+ } catch (e) {
+ return false;
+ }
+});
+
const props = defineProps({
createTestingAccount: {
type: Function,
@@ -124,7 +166,23 @@ const props = defineProps({
type: Boolean,
required: false,
},
+ changeSessionAuthorization: {
+ type: Function,
+ required: false,
+ },
});
+
+watch(
+ () => props.show,
+ (show) => {
+ if (show) {
+ console.log("current extension account: ", accountStore.getAddress);
+ currentExtensionAccount.value = accountStore.getAddress;
+ //selectedExtensionAccount.value = "";
+ }
+ },
+);
+
const hasCreateTestingAccountFn = computed(
() => typeof props.createTestingAccount === "function",
);
@@ -139,10 +197,15 @@ const closeProxy = () => {
};
watch(selectedExtensionAccount, async (selectedAddress) => {
- if (selectedAddress) {
+ if (selectedAddress && selectedExtensionAccountIsNew.value) {
props.onExtensionAccountChange(selectedAddress);
}
});
-
+
diff --git a/components/overlays/SessionProxiesOverlay.vue b/components/overlays/SessionProxiesOverlay.vue
new file mode 100644
index 0000000..2851369
--- /dev/null
+++ b/components/overlays/SessionProxiesOverlay.vue
@@ -0,0 +1,384 @@
+
+
+
+
+ For a smooth experience with minimal signing interaction we recommend
+ that your authorize a session key. It will be cached confidentially on
+ Incognitee and loaded automatically on your next visit.
+
+
+ Registering a session key costs a fee of
+ {{ formatDecimalBalance(INCOGNITEE_TX_FEE) }}
+ {{ accountStore.getSymbol }} and a deposit of
+ {{ INCOGNITEE_SESSION_PROXY_DEPOSIT }} {{ accountStore.getSymbol }} will
+ be reserved.
+
+
+
+
+
+
+ Continue Without Session Proxy
+
+
+
+
+
+
+
+
+
+
diff --git a/components/tabs/MessagingTab.vue b/components/tabs/MessagingTab.vue
index 899144e..b125602 100644
--- a/components/tabs/MessagingTab.vue
+++ b/components/tabs/MessagingTab.vue
@@ -402,6 +402,7 @@ import { useNotes } from "@/store/notes.ts";
import { Note, NoteDirection } from "@/lib/notes";
import { divideBigIntToFloat } from "@/helpers/numbers";
import NoteDetailsOverlay from "~/components/overlays/NoteDetailsOverlay.vue";
+import { SessionProxyRole } from "~/lib/sessionProxyStorage";
const identityLut = [...polkadotPeopleIdentities, ...wellKnownIdentities];
@@ -580,7 +581,6 @@ const submitSendForm = () => {
const sendPrivately = async () => {
console.log("sending message on incognitee");
txStatus.value = "⌛ sending message privately on incognitee";
- const amount = BigInt(0);
const account = accountStore.account;
if (
accountStore.getDecimalBalanceTransferable(incogniteeSidechain.value) <
@@ -608,16 +608,18 @@ const sendPrivately = async () => {
);
await incogniteeStore.api
- .trustedBalanceTransfer(
+ .trustedSendNote(
account,
incogniteeStore.shard,
incogniteeStore.fingerprint,
accountStore.getAddress,
conversationAddress.value,
- amount,
note,
{
signer: accountStore.injector?.signer,
+ delegate: accountStore.sessionProxyForRole(
+ SessionProxyRole.NonTransfer,
+ ),
nonce: nonce,
},
)
@@ -636,7 +638,7 @@ const handleTopResult = (result, successMsg?) => {
txStatus.value =
"😀 included in sidechain block: " + result.status.asInSidechainBlock;
}
- //update history to see successfuly action immediately
+ //update history to see successful action immediately
props.updateNotes();
return;
}
diff --git a/components/tabs/VouchersTab.vue b/components/tabs/VouchersTab.vue
index 99241ec..bbafb42 100644
--- a/components/tabs/VouchersTab.vue
+++ b/components/tabs/VouchersTab.vue
@@ -378,6 +378,7 @@ import {
forgetAllVouchersForShard,
forgetVoucherForShard,
} from "~/lib/voucherStorage";
+import { SessionProxyRole } from "~/lib/sessionProxyStorage";
const accountStore = useAccount();
const incogniteeStore = useIncognitee();
@@ -488,6 +489,7 @@ const fundNewVoucher = async () => {
note,
{
signer: accountStore.injector?.signer,
+ delegate: accountStore.sessionProxyForRole(SessionProxyRole.Any),
nonce: nonce,
},
)
diff --git a/components/tabs/WalletTab.vue b/components/tabs/WalletTab.vue
index b16a6ed..08a85af 100644
--- a/components/tabs/WalletTab.vue
+++ b/components/tabs/WalletTab.vue
@@ -2,7 +2,7 @@
-
-
{
txStatus.value =
"😀 included in sidechain block: " + result.status.asInSidechainBlock;
}
- //update history to see successfuly action immediately
+ //update history to see successful action immediately
props.updateNotes();
return;
}
@@ -1284,6 +1279,7 @@ const unshield = async () => {
amount,
{
signer: accountStore.injector?.signer,
+ delegate: accountStore.sessionProxyForRole(SessionProxyRole.Any),
nonce: nonce,
},
)
@@ -1332,6 +1328,7 @@ const sendPrivately = async () => {
note,
{
signer: accountStore.injector?.signer,
+ delegate: accountStore.sessionProxyForRole(SessionProxyRole.Any),
nonce: nonce,
},
)
@@ -1359,6 +1356,9 @@ const submitGuess = async () => {
guess.value,
{
signer: accountStore.injector?.signer,
+ delegate: accountStore.sessionProxyForRole(
+ SessionProxyRole.NonTransfer,
+ ),
nonce: nonce,
},
)
@@ -1431,7 +1431,7 @@ const closePrivacyInfo = () => {
const showObtainTokenOverlay = ref(false);
const openObtainTokenOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1443,7 +1443,7 @@ const closeObtainTokenOverlay = () => {
const showShieldOverlay = ref(false);
const openShieldOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1458,7 +1458,7 @@ const closeShieldOverlay = () => {
const showFaucetOverlay = ref(false);
const openFaucetOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1470,7 +1470,7 @@ const closeFaucetOverlay = () => {
const showUnshieldOverlay = ref(false);
const openUnshieldOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1484,7 +1484,7 @@ const closeUnshieldOverlay = () => {
};
const showReceiveOverlay = ref(false);
const openReceiveOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1495,7 +1495,7 @@ const closeReceiveOverlay = () => {
};
const showPrivateSendOverlay = ref(false);
const openPrivateSendOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1517,7 +1517,7 @@ const closePrivateSendOverlay = () => {
const showGuessTheNumberOverlay = ref(false);
const openGuessTheNumberOverlay = () => {
- if (!enableActions.value) {
+ if (!props?.enableActions) {
console.error("network not live");
return;
}
@@ -1599,10 +1599,10 @@ const props = defineProps({
type: Function,
required: true,
},
-});
-
-const enableActions = computed(() => {
- return isLive.value || forceLive.value;
+ enableActions: {
+ type: Boolean,
+ required: true,
+ },
});
diff --git a/configs/incognitee.ts b/configs/incognitee.ts
index e96cf10..9d8ed98 100644
--- a/configs/incognitee.ts
+++ b/configs/incognitee.ts
@@ -5,3 +5,5 @@ export const INCOGNITEE_GTN_GUESS_FEE = 0.1; // TEER or PAS, decimals are respec
export const INCOGNITEE_UNSHIELDING_FEE = 3 * INCOGNITEE_TX_FEE; // TEER or PAS, decimals are respected
export const INCOGNITEE_SHIELDING_FEE_FRACTION = 0.00175; // 0.175% of the shielding amount
+
+export const INCOGNITEE_SESSION_PROXY_DEPOSIT = 0.5; // TEER or PAS, decimals are respected
diff --git a/lib/sessionProxyStorage.ts b/lib/sessionProxyStorage.ts
new file mode 100644
index 0000000..9729649
--- /dev/null
+++ b/lib/sessionProxyStorage.ts
@@ -0,0 +1,34 @@
+export enum SessionProxyRole {
+ ReadBalance = "readBalance",
+ ReadAny = "readAny",
+ NonTransfer = "nonTransfer",
+ Any = "any",
+ TransferAllowance = "transferAllowance",
+}
+
+export const sessionProxyRoleOrder = [
+ SessionProxyRole.ReadBalance,
+ SessionProxyRole.ReadAny,
+ SessionProxyRole.NonTransfer,
+ SessionProxyRole.TransferAllowance,
+ SessionProxyRole.Any,
+];
+
+export function isRoleAtLeast(
+ role1: SessionProxyRole,
+ role2: SessionProxyRole,
+): boolean {
+ return roleOrder.indexOf(role1) >= roleOrder.indexOf(role2);
+}
+
+export class SessionProxyCredentials {
+ role: SessionProxyRole;
+ expiry: Date;
+ seed: Uint8Array;
+
+ constructor(role: SessionProxyRole, expiry: Date, seed: Uint8Array) {
+ this.role = role;
+ this.expiry = expiry;
+ this.seed = seed;
+ }
+}
diff --git a/package.json b/package.json
index fcc34cd..986b5b3 100644
--- a/package.json
+++ b/package.json
@@ -39,8 +39,8 @@
"vue-router": "^4.3.2"
},
"dependencies": {
- "@encointer/util": "^0.18.0-alpha.2",
- "@encointer/worker-api": "^0.18.0-alpha.2",
+ "@encointer/util": "^0.18.0",
+ "@encointer/worker-api": "^0.18.0",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@headlessui/vue": "^1.7.22",
"@heroicons/vue": "^2.1.3",
diff --git a/pages/index.vue b/pages/index.vue
index 51448a8..007c60a 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -12,6 +12,7 @@
ref="walletTabRef"
:updateNotes="updateNotes"
:fetchOlderBucket="fetchOlderBucket"
+ :enableActions="enableActions"
/>
@@ -97,6 +98,14 @@
+
+
+
@@ -111,7 +121,8 @@
import WalletTab from "~/components/tabs/WalletTab.vue";
import VouchersTab from "~/components/tabs/VouchersTab.vue";
import ChooseWalletOverlay from "~/components/overlays/ChooseWalletOverlay.vue";
-import { computed } from "vue";
+import SessionProxiesOverlay from "~/components/overlays/SessionProxiesOverlay.vue";
+import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { chainConfigs } from "@/configs/chains.ts";
import { useAccount } from "@/store/account.ts";
import { useIncognitee } from "@/store/incognitee.ts";
@@ -126,7 +137,6 @@ import {
mnemonicToMiniSecret,
} from "@polkadot/util-crypto";
import { useInterval } from "@vueuse/core";
-import { onUnmounted, onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router";
import { eventBus } from "@/helpers/eventBus";
import {
@@ -134,16 +144,17 @@ import {
injectorForAddress,
} from "@/lib/signerExtensionUtils";
import {
- loadEnv,
- shieldingTarget,
- incogniteeSidechain,
incogniteeShard,
+ incogniteeSidechain,
isLive,
+ loadEnv,
+ shieldingTarget,
} from "@/lib/environmentConfig";
import { useSystemHealth } from "@/store/systemHealth";
import { useNotes } from "~/store/notes";
import { formatMoment } from "~/helpers/date";
import { Note, NoteDirection } from "~/lib/notes";
+import { SessionProxyRole } from "@/lib/sessionProxyStorage.ts";
import MessagingTab from "~/components/tabs/MessagingTab.vue";
import SwapTab from "~/components/tabs/SwapTab.vue";
import GovTab from "~/components/tabs/GovTab.vue";
@@ -168,9 +179,11 @@ const shieldingTargetApi = ref(null);
const isProd = computed(
() => chainConfigs[shieldingTarget.value].faucetUrl === undefined,
);
+
const onExtensionAccountChange = async (selectedAddress) => {
dropSubscriptions();
console.log("user selected extension account:", selectedAddress);
+ accountStore.resetState();
accountStore.setAccount(selectedAddress.toString());
accountStore.setInjector(await injectorForAddress(accountStore.getAddress));
isUpdatingIncogniteeBalance.value = false;
@@ -205,7 +218,7 @@ const fetchIncogniteeBalance = async () => {
);
}
getterMap[accountStore.account] =
- await incogniteeStore.api.accountInfoGetter(
+ await incogniteeStore.api.accountInfoAndSessionProxiesGetter(
accountStore.account,
incogniteeStore.shard,
{ signer: injector?.signer },
@@ -226,10 +239,14 @@ const fetchIncogniteeBalance = async () => {
await getterMap[accountStore.account]
.send()
- .then((accountInfo) => {
+ .then((accountInfoAndSessionProxies) => {
+ const accountInfo = accountInfoAndSessionProxies.account_info;
+ const proxies = accountInfoAndSessionProxies.session_proxies;
console.debug(
`current account info L2: ${accountInfo} on shard ${incogniteeStore.shard}`,
);
+ console.debug(`session proxies: ${proxies}`);
+ storeSessionProxies(proxies);
accountStore.setBalanceFree(
BigInt(accountInfo.data.free),
incogniteeSidechain.value,
@@ -241,6 +258,15 @@ const fetchIncogniteeBalance = async () => {
isFetchingIncogniteeBalance.value = false;
isUpdatingIncogniteeBalance.value = false;
isChoosingAccount.value = false;
+ if (
+ proxies.length == 0 &&
+ accountStore.hasInjector &&
+ !accountStore.hasDeclinedSessionProxy &&
+ accountStore.getDecimalBalanceFree(incogniteeSidechain.value) > 0
+ ) {
+ openAuthorizeSessionOverlay();
+ }
+ //openAuthorizeSessionOverlay();
})
.catch((err) => {
console.error(`[fetchIncogniteeBalance] error ${err}`);
@@ -248,6 +274,18 @@ const fetchIncogniteeBalance = async () => {
});
};
+const storeSessionProxies = (proxies) => {
+ for (const proxy of proxies) {
+ const localKeyring = new Keyring({ type: "sr25519" });
+ const seed = hexToU8a(proxy.seed.toString());
+ const account = localKeyring.addFromSeed(seed);
+ accountStore.addSessionProxy(
+ account,
+ seed,
+ proxy.role.toString() as SessionProxyRole,
+ );
+ }
+};
const fetchNetworkStatus = async () => {
const promises = [];
if (shieldingTargetApi.value?.isReady) {
@@ -335,10 +373,9 @@ const fetchOlderBucket = async () => {
/// returns the date as moment before which all notes have been purged from sidechain state
const oldestMomentInNoteBuckets = computed(() => {
- console.log(
- "oldest moment is " + noteBucketsInfo.value?.first.unwrap().begins_at,
- );
- return noteBucketsInfo.value?.first.unwrap().begins_at?.toNumber();
+ const beginsAt = noteBucketsInfo.value?.first.unwrap().begins_at;
+ console.log("oldest moment is " + beginsAt?.toNumber());
+ return beginsAt ? beginsAt.toNumber() : NaN;
});
const bucketsCount = computed(() => {
@@ -352,10 +389,12 @@ const bucketsCount = computed(() => {
const unfetchedBucketsCount = computed(() => {
if (!noteBucketsInfo.value) return 0;
- return (
- firstNoteBucketIndexFetched.value ? firstNoteBucketIndexFetched.value -
- noteBucketsInfo.value.first.unwrap().index : noteBucketsInfo.value.last.unwrap().index - noteBucketsInfo.value.first.unwrap().index +1
- );
+ return firstNoteBucketIndexFetched.value
+ ? firstNoteBucketIndexFetched.value -
+ noteBucketsInfo.value.first.unwrap().index
+ : noteBucketsInfo.value.last.unwrap().index -
+ noteBucketsInfo.value.first.unwrap().index +
+ 1;
});
const fetchIncogniteeNotes = async (
@@ -372,10 +411,17 @@ const fetchIncogniteeNotes = async (
return;
}
const mapKey = `notesFor:${accountStore.account}:${bucketIndex}`;
+ const sessionProxy = accountStore.sessionProxyForRole(
+ SessionProxyRole.ReadAny,
+ );
+ console.debug(
+ "[fetchIncogniteeNotes] sessionProxy: " + sessionProxy?.address,
+ );
const injector = accountStore.hasInjector ? accountStore.injector : null;
+ console.debug("[fetchIncogniteeNotes] injector: " + injector);
try {
if (!getterMap[mapKey]) {
- if (injector) {
+ if (injector && sessionProxy == null) {
if (skip_if_signer_needed) {
console.log(
"skipping automated fetchIncogniteeNotes because signer is needed",
@@ -391,7 +437,7 @@ const fetchIncogniteeNotes = async (
accountStore.account,
bucketIndex,
incogniteeStore.shard,
- { signer: injector?.signer },
+ { delegate: sessionProxy, signer: injector?.signer },
);
} else {
console.debug(`fetching incognitee notes using cached getter`);
@@ -521,6 +567,43 @@ const fetchIncogniteeNotes = async (
`[${formatMoment(note.timestamp?.toNumber())}] unknown relation to transfer: ${typedCall}`,
);
}
+ } else if (call.isSendNote) {
+ const typedCall = call.asSendNote;
+ console.debug(
+ `[${formatMoment(note.timestamp?.toNumber())}] send note: ${typedCall}`,
+ );
+ const from = encodeAddress(
+ typedCall[0],
+ accountStore.getSs58Format,
+ );
+ const to = encodeAddress(typedCall[1], accountStore.getSs58Format);
+ if (from === accountStore.getAddress) {
+ noteStore.addNote(
+ new Note(
+ "Outgoing Note",
+ NoteDirection.Outgoing,
+ to,
+ BigInt(0),
+ new Date(note.timestamp?.toNumber()),
+ typedCall[2].toString(),
+ ),
+ );
+ } else if (to === accountStore.getAddress) {
+ noteStore.addNote(
+ new Note(
+ "Incoming Note",
+ NoteDirection.Incoming,
+ from,
+ BigInt(0),
+ new Date(note.timestamp?.toNumber()),
+ typedCall[2].toString(),
+ ),
+ );
+ } else {
+ console.error(
+ `[${formatMoment(note.timestamp?.toNumber())}] unknown relation to transfer: ${typedCall}`,
+ );
+ }
} else if (call.isGuessTheNumber) {
const typedCall = call.asGuessTheNumber.asGuess;
console.debug(
@@ -536,6 +619,25 @@ const fetchIncogniteeNotes = async (
null,
),
);
+ } else if (call.isAddSessionProxy) {
+ const typedCall = call.asAddSessionProxy;
+ const proxy = encodeAddress(
+ typedCall[1],
+ accountStore.getSs58Format,
+ );
+ console.debug(
+ `[${formatMoment(note.timestamp?.toNumber())}] add session proxy: ${typedCall}`,
+ );
+ noteStore.addNote(
+ new Note(
+ `Add Session Proxy (${typedCall[2].role})`,
+ NoteDirection.None,
+ proxy,
+ null,
+ new Date(note.timestamp?.toNumber()),
+ null,
+ ),
+ );
} else {
console.error(
`[${formatMoment(note.timestamp?.toNumber())}] unknown call: ${call}`,
@@ -787,6 +889,12 @@ const dropSubscriptions = () => {
accountStore.setInjector(null);
};
+const changeSessionProxies = () => {
+ closeChooseWalletOverlay();
+ isUpdatingIncogniteeBalance.value = false;
+ openAuthorizeSessionOverlay();
+};
+
const createTestingAccount = async () => {
await cryptoWaitReady().then(() => {
dropSubscriptions();
@@ -826,6 +934,20 @@ const closeNewWalletOverlay = () => {
showNewWalletOverlay.value = false;
};
+const showAuthorizeSessionOverlay = ref(false);
+const openAuthorizeSessionOverlay = () => {
+ if (!enableActions.value) {
+ console.error("network not live");
+ return;
+ }
+ showAuthorizeSessionOverlay.value = true;
+};
+const closeAuthorizeSessionOverlay = (optout: boolean) => {
+ if (optout) {
+ accountStore.declineSessionProxy();
+ }
+ showAuthorizeSessionOverlay.value = false;
+};
const showChooseWalletOverlay = ref(false);
const openChooseWalletOverlay = () => {
if (!enableActions.value) {
diff --git a/store/account.ts b/store/account.ts
index 5aebd56..575de1f 100644
--- a/store/account.ts
+++ b/store/account.ts
@@ -5,6 +5,10 @@ import type { InjectedExtension } from "@polkadot/extension-inject/types";
import { ChainId } from "@/configs/chains";
import { encodeAddress } from "@polkadot/util-crypto";
import { divideBigIntToFloat, formatDecimalBalance } from "@/helpers/numbers";
+import {
+ SessionProxyRole,
+ sessionProxyRoleOrder,
+} from "@/lib/sessionProxyStorage.ts";
export const useAccount = defineStore("account", {
state: () => ({
@@ -12,6 +16,12 @@ export const useAccount = defineStore("account", {
account: null,
// optional signer extension
injector: null,
+ // optional session proxy credentials
+ sessionProxies: >{},
+ // optional session proxy minisecrets
+ sessionProxySeeds: >{},
+ // remember if the user has declined creating a proxy
+ sessionProxyDeclined: false,
// free balance per chain
balanceFree: >{},
// reserved balance per chain
@@ -54,6 +64,53 @@ export const useAccount = defineStore("account", {
hasInjector({ injector }): boolean {
return injector != null;
},
+ hasSessionProxyForRole({
+ sessionProxies,
+ }): (role: SessionProxyRole) => boolean {
+ return (role: SessionProxyRole): boolean => {
+ return sessionProxies[role] != null;
+ };
+ },
+ hasDeclinedSessionProxy({ sessionProxyDeclined }): boolean {
+ return sessionProxyDeclined;
+ },
+ /// Returns the weakest session proxy which is authorized for at least the requested role
+ sessionProxyForRole({
+ sessionProxies,
+ }): (role: SessionProxyRole) => AddressOrPair | null {
+ return (role: SessionProxyRole): AddressOrPair | null => {
+ const startIndex = sessionProxyRoleOrder.indexOf(role);
+ if (startIndex === -1) return null;
+ for (let i = startIndex; i < sessionProxyRoleOrder.length; i++) {
+ const currentRole = sessionProxyRoleOrder[i];
+ if (sessionProxies[currentRole]) {
+ return sessionProxies[currentRole];
+ }
+ }
+ return null;
+ };
+ },
+ /// Returns the most powerful session proxy
+ sessionProxyBest({
+ sessionProxies,
+ }): () => [AddressOrPair | null, SessionProxyRole | null] {
+ return (): [AddressOrPair | null, SessionProxyRole | null] => {
+ for (let i = sessionProxyRoleOrder.length - 1; i >= 0; i--) {
+ const currentRole = sessionProxyRoleOrder[i];
+ if (sessionProxies[currentRole]) {
+ return [sessionProxies[currentRole], currentRole];
+ }
+ }
+ return [null, null];
+ };
+ },
+ sessionProxySeed({
+ sessionProxySeeds,
+ }): (proxy: AddressOrPair) => Uint8Array {
+ return (proxy: AddressOrPair): Uint8Array => {
+ return sessionProxySeeds[proxy];
+ };
+ },
formatBalanceFree({ balanceFree, decimals }) {
return (chain: ChainId): string => {
if (!balanceFree[chain]) return "0.000";
@@ -117,12 +174,33 @@ export const useAccount = defineStore("account", {
},
},
actions: {
+ /// call this when account changes to clear all account-related state
+ resetState() {
+ this.sessionProxyDeclined = false;
+ this.sessionProxies = {};
+ this.injector = null;
+ this.BalanceFree = {};
+ this.BalanceReserved = {};
+ this.BalanceFrozen = {};
+ },
setAccount(account: AddressOrPair) {
this.account = account;
},
setInjector(injector: InjectedExtension) {
this.injector = injector;
},
+ /// sticky decline for adding session proxies
+ declineSessionProxy() {
+ this.sessionProxyDeclined = true;
+ },
+ addSessionProxy(
+ sessionProxy: AddressOrPair,
+ seed: Uint8Array,
+ role: SessionProxyRole,
+ ) {
+ this.sessionProxies[role] = sessionProxy;
+ this.sessionProxySeeds[sessionProxy] = seed;
+ },
setBalanceFree(balance: BigInt, chain: ChainId) {
this.balanceFree[chain] = balance;
},
diff --git a/store/notes.ts b/store/notes.ts
index ce4e934..2e6737f 100644
--- a/store/notes.ts
+++ b/store/notes.ts
@@ -17,7 +17,10 @@ export const useNotes = defineStore("notes", {
},
getFinancialNotes() {
return this.getSortedNotesNewestFirst.filter(
- (note) => (note.amount > 0) | note.category.includes("Guess"),
+ (note) =>
+ (note.amount > 0) |
+ note.category.includes("Guess") |
+ note.category.includes("Session Proxy"),
);
},
getConversationCounterparties() {
diff --git a/yarn.lock b/yarn.lock
index 2d55e21..900f629 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -531,32 +531,32 @@ __metadata:
languageName: node
linkType: hard
-"@encointer/node-api@npm:^0.18.0-alpha.2":
- version: 0.18.0-alpha.2
- resolution: "@encointer/node-api@npm:0.18.0-alpha.2"
+"@encointer/node-api@npm:^0.18.0":
+ version: 0.18.0
+ resolution: "@encointer/node-api@npm:0.18.0"
dependencies:
- "@encointer/types": "npm:^0.18.0-alpha.2"
+ "@encointer/types": "npm:^0.18.0"
"@polkadot/api": "npm:^11.2.1"
tslib: "npm:^2.6.2"
- checksum: 10c0/383ac0109d83e5b908e0a33c648dee678773a674b86234f03f0694f5de7d370dac20bcde45f49335a2e5ddbfcd7ed62422fe8528b00cc7a9cd1acecae57616b3
+ checksum: 10c0/e9cbf01b15a622b5d4a5c1b30e0257ce3d5aaeb5decf9aee05f6cc9c178c36b3efe1bf454422becf0150f86eedbc4f12948387e01e3e6e0a7489d8e3eb9c50e9
languageName: node
linkType: hard
-"@encointer/types@npm:^0.18.0-alpha.2":
- version: 0.18.0-alpha.2
- resolution: "@encointer/types@npm:0.18.0-alpha.2"
+"@encointer/types@npm:^0.18.0":
+ version: 0.18.0
+ resolution: "@encointer/types@npm:0.18.0"
dependencies:
"@polkadot/api": "npm:^11.2.1"
"@polkadot/types": "npm:^11.2.1"
"@polkadot/types-codec": "npm:^11.2.1"
"@polkadot/util": "npm:^12.6.2"
- checksum: 10c0/dc4ba196329103de0cd3326f0d72eefee57b1dc347ceb59dfbac37828cb837c47a581bad10b4b483b7536fb5a8fd8a29fe055862a70092703507ab9169b528ac
+ checksum: 10c0/6001f1c4f76e55013e685c3b0ecb3da5cede271450e115974fbe2df68ccd868f9b2b67947e3bb38a8072e4666020c9cb394c9887f15be28fae6ec1b9b44add90
languageName: node
linkType: hard
-"@encointer/util@npm:^0.18.0-alpha.2":
- version: 0.18.0-alpha.2
- resolution: "@encointer/util@npm:0.18.0-alpha.2"
+"@encointer/util@npm:^0.18.0":
+ version: 0.18.0
+ resolution: "@encointer/util@npm:0.18.0"
dependencies:
"@babel/runtime": "npm:^7.18.9"
"@polkadot/util": "npm:^12.6.2"
@@ -564,17 +564,17 @@ __metadata:
"@types/bn.js": "npm:^5.1.5"
assert: "npm:^2.0.0"
bn.js: "npm:^5.2.1"
- checksum: 10c0/128a8b3835afd403cace1de6ea102bdfd88c64e3a360ea09ccfeeb513c365d978699d44110f3a2ff4b5197594ea1065bb3a179c1cc0774ba6d89ed983ebec95f
+ checksum: 10c0/ad51ce72bb6acca6313f18fd02b33fc6365806b779c8acc653dc784ee9d6661a90d332aac0188e7afc0c0076daaf36ca7fde4ba9b917bfa09c8cdf376925a1cc
languageName: node
linkType: hard
-"@encointer/worker-api@npm:^0.18.0-alpha.2":
- version: 0.18.0-alpha.2
- resolution: "@encointer/worker-api@npm:0.18.0-alpha.2"
+"@encointer/worker-api@npm:^0.18.0":
+ version: 0.18.0
+ resolution: "@encointer/worker-api@npm:0.18.0"
dependencies:
- "@encointer/node-api": "npm:^0.18.0-alpha.2"
- "@encointer/types": "npm:^0.18.0-alpha.2"
- "@encointer/util": "npm:^0.18.0-alpha.2"
+ "@encointer/node-api": "npm:^0.18.0"
+ "@encointer/types": "npm:^0.18.0"
+ "@encointer/util": "npm:^0.18.0"
"@peculiar/webcrypto": "npm:^1.4.6"
"@polkadot/api": "npm:^11.2.1"
"@polkadot/keyring": "npm:^12.6.2"
@@ -589,7 +589,7 @@ __metadata:
tslib: "npm:^2.6.2"
peerDependencies:
"@polkadot/x-randomvalues": ^12.3.2
- checksum: 10c0/3d2f835527d75c6b1b31550c0e7dbaeb98c97248d2bffc6b766fea8ac219d52e50ed57832c44a77c07f9e055c3eb7cf6f93a6cb14f27ba33600e9d5113df7b17
+ checksum: 10c0/0c0332ff48f3e11b47817d6eff9e8b1bf75ec1c014e350f65733390a72fe92da6c750a1d43a3ddc2c6f87bc2a7f2403feaf0dd3fcd70a72a6ef44c5f41a3c1ee
languageName: node
linkType: hard
@@ -10006,8 +10006,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "nuxt-app@workspace:."
dependencies:
- "@encointer/util": "npm:^0.18.0-alpha.2"
- "@encointer/worker-api": "npm:^0.18.0-alpha.2"
+ "@encointer/util": "npm:^0.18.0"
+ "@encointer/worker-api": "npm:^0.18.0"
"@esbuild-plugins/node-globals-polyfill": "npm:^0.2.3"
"@headlessui/vue": "npm:^1.7.22"
"@heroicons/vue": "npm:^2.1.3"