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

Add support for browser extensions #62

Merged
merged 19 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"vue-router": "^4.3.2"
},
"dependencies": {
"@encointer/worker-api": "^0.14.2",
"@encointer/util": "^0.15.0",
"@encointer/worker-api": "^0.15.0",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@headlessui/vue": "^1.7.22",
"@heroicons/vue": "^2.1.3",
Expand All @@ -48,7 +49,7 @@
"@nuxt/ui": "^2.15.2",
"@pinia/nuxt": "^0.5.1",
"@polkadot/api": "^11.2.1",
"@polkadot/extension-dapp": "^0.51.1",
"@polkadot/extension-dapp": "^0.47.6",
brenzi marked this conversation as resolved.
Show resolved Hide resolved
"@polkadot/keyring": "^12.6.2",
"@polkadot/util": "^12.6.2",
"@polkadot/util-crypto": "^12.6.2",
Expand Down
183 changes: 141 additions & 42 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,7 @@ const accountStore = useAccount();
const incogniteeStore = useIncognitee();
const isFetchingPaseoBalance = ref(true);
const isFetchingIncogniteeBalance = ref(true);
const isUpdatingIncogniteeBalance = ref(false);
brenzi marked this conversation as resolved.
Show resolved Hide resolved

const existential_deposit_paseo = 10000000000;
const txStatus = ref("");
Expand Down Expand Up @@ -1585,32 +1586,42 @@ const shield = async () => {
const wsProvider = new WsProvider("wss://rpc.ibp.network/paseo");
const api = await ApiPromise.create({ provider: wsProvider });
console.log("api initialized for shielding");
await api.tx.balances
.transferKeepAlive(incogniteeStore.vault, amount)
.signAndSend(accountStore.account, txResHandlerPaseo)
.catch(txErrHandlerPaseo);

api.tx.balances
.transferKeepAlive(incogniteeStore.vault, amount)
.signAsync(accountStore.account, {signer: accountStore.injector?.signer})
.then((tx) => tx.send(txResHandlerPaseo))
.catch(txErrHandlerPaseo);
}
};

const unshield = () => {
console.log("will unshield 30% of your private funds to same account on L1");
txStatus.value = "⌛ will unshield to L1";
const balance = accountStore.incogniteeBalance;
const amount = Math.pow(10, 10) * unshieldAmount.value;
const signer = accountStore.account;
const account = accountStore.account;
console.log(
`sending ${formatBalance(amount)} from ${
signer.address
accountStore.getAddress
} privately to ${recipientAddress.value} on L1 (shard: ${incogniteeStore.shard}`,
);

// console.log(`[unshield] mrenclave: ${incogniteeStore.fingerprint}`);
// console.log(`[unshield] shard: ${incogniteeStore.shard}`);

incogniteeStore.api
.balanceUnshieldFunds(
signer,
account,
incogniteeStore.shard,
incogniteeStore.fingerprint,
signer.address,
accountStore.getAddress,
recipientAddress.value,
amount,
{
signer: accountStore.injector?.signer,
// was used to test because the getters don't work yet.
// nonce: incogniteeStore.api.createType('u32', 1)
brenzi marked this conversation as resolved.
Show resolved Hide resolved
}
)
.then((hash) => {
txStatus.value = "😀 Triggered unshielding of funds successfully.";
Expand All @@ -1622,43 +1633,80 @@ const sendPrivately = () => {
console.log("sending funds on incognitee");
txStatus.value = "⌛ sending funds privately on incognitee";
const amount = Math.pow(10, 10) * sendAmount.value;
const signer = accountStore.account;
const account = accountStore.account;
console.log(
`sending ${formatBalance(amount)} from ${signer.address} privately to ${recipientAddress.value}`,
`sending ${formatBalance(amount)} from ${account.address} privately to ${recipientAddress.value}`,
);
incogniteeStore.api
.trustedBalanceTransfer(
signer,
incogniteeStore.shard,
incogniteeStore.fingerprint,
signer.address,
recipientAddress.value,
amount,
)
.then((hash) => {
console.log(`trustedOperationHash: ${hash}`);
txStatus.value = "😀 Success";
});

incogniteeStore.api
.trustedBalanceTransfer(
account,
incogniteeStore.shard,
incogniteeStore.fingerprint,
accountStore.getAddress,
recipientAddress.value,
amount,
{ signer: accountStore.injector?.signer }
)
.then((hash) => {
console.log(`trustedOperationHash: ${hash}`);
txStatus.value = "😀 Success";
});
};

let getter;

const fetchIncogniteeBalance = async () => {
if (!incogniteeStore.apiReady) return;
if (!accountStore.account) return;
incogniteeStore.api
.getBalance(accountStore.account, incogniteeStore.shard)

if (isUpdatingIncogniteeBalance.value == true) {
console.log("[fetchIncogniteeBalance] already updating returning...")
return;
}

isUpdatingIncogniteeBalance.value = true;

console.log(`fetching incognitee balance: is injected ${accountStore.hasInjector}`);

const injector = accountStore.hasInjector ? accountStore.injector : null
console.log(`fetching incognitee balance: injector ${JSON.stringify(injector)}}`);
console.log(`fetching incognitee balance: injector ${JSON.stringify(injector?.signer)}}`);

try {
if (getter === undefined) {
getter = await incogniteeStore.api.getBalanceGetter(accountStore.account, incogniteeStore.shard, { signer: injector?.signer });
}
} catch (e) {
// this will be the case if we click on cancel in the extension popup.
console.error(e);
isUpdatingIncogniteeBalance.value = false;
return;
brenzi marked this conversation as resolved.
Show resolved Hide resolved
}


await getter
.send()
.then((balance) => {
console.log(
`current account balance L2: ${balance} on shard ${incogniteeStore.shard}`,
`current account balance L2: ${balance} on shard ${incogniteeStore.shard}`,
);
accountStore.setIncogniteeBalance(balance);
isFetchingIncogniteeBalance.value = false;
isUpdatingIncogniteeBalance.value = false;
})
.catch((err) => {
console.error(`[fetchIncogniteeBalance] error ${err}`);
isUpdatingIncogniteeBalance.value = false;
});

};

const pollCounter = useInterval(2000);

watch(pollCounter, async () => {
console.log("ping: " + pollCounter.value);

await fetchIncogniteeBalance();
});

Expand All @@ -1679,10 +1727,10 @@ watch(accountStore, async () => {
const wsProvider = new WsProvider("wss://rpc.ibp.network/paseo");
api = await ApiPromise.create({ provider: wsProvider });
api.query.system.account(
accountStore.account.address,
accountStore.getAddress,
({ data: { free: currentFree } }) => {
console.log("paseo balance:" + currentFree);
accountStore.paseoBalance = Number(currentFree);
accountStore.setPaseoBalance(Number(currentFree));
isFetchingPaseoBalance.value = false;
},
);
Expand All @@ -1701,36 +1749,87 @@ const copyOwnAddressToClipboard = () => {
),
);
};
import {web3Accounts, web3Enable, web3FromAddress, web3FromSource} from '@polkadot/extension-dapp';

onMounted(() => {
onMounted(async () => {
incogniteeStore.initializeApi();

const seedHex = router.currentRoute.value.query.seed;
const injectedAddress = router.currentRoute.value.query.address;

if (seedHex) {
console.log("found seed in url: " + seedHex);
cryptoWaitReady().then(() => {
const localKeyring = new Keyring({ type: "sr25519" });
const account = localKeyring.addFromSeed(hexToU8a(seedHex));
accountStore.setAccount(account);
});
} else if (injectedAddress) {
// returns an array of all the injected sources
// (this needs to be called first, before other requests)
const allInjected = await web3Enable('Incognitee Campaign Page');
console.log(`AllInjected: ${JSON.stringify(allInjected)}`);

// returns an array of { address, meta: { name, source } }
// meta.source contains the name of the extension that provides this account
const allAccounts = await web3Accounts();
console.log(`All webAccounts: ${JSON.stringify(allAccounts)}`);

accountStore.setAccount(injectedAddress.toString());
const injector = await web3FromAddress(accountStore.getAddress)
console.log(`setting injector: ${JSON.stringify(injector)}`)
console.log(`setting injector: ${JSON.stringify(injector.signer)}`)
accountStore.setInjector(injector);
} else {
console.log("no seed found in url. will automatically create fresh wallet");
console.log("no seed found in url. Will try to inject from extensions");
// returns an array of all the injected sources
// (this needs to be called first, before other requests)
const allInjected = await web3Enable('Incognitee Campaign Page');
console.log(`AllInjected: ${JSON.stringify(allInjected)}`);

// returns an array of { address, meta: { name, source } }
// meta.source contains the name of the extension that provides this account
const allAccounts = await web3Accounts();
console.log(`All webAccounts: ${JSON.stringify(allAccounts)}`);

const firstAddress = allAccounts[1].address;
console.log(`first address: ${firstAddress}`)

accountStore.setAccount(firstAddress);

const injector = await web3FromSource(allAccounts[1].meta.source);
console.log(`setting injector: ${JSON.stringify(injector)}`)
console.log(`setting injector: ${JSON.stringify(injector.signer)}`)

accountStore.setInjector(injector);

cryptoWaitReady().then(() => {
const generatedMnemonic = mnemonicGenerate();
const localKeyring = new Keyring({ type: "sr25519", ss58Format: 42 });
const newAccount = localKeyring.addFromMnemonic(generatedMnemonic, {
name: "fresh",
});
const seed = mnemonicToMiniSecret(generatedMnemonic);
const privateKeyHex = u8aToHex(seed);
console.log(`Private Key in Hex: ${privateKeyHex}`);
// change url to contain new seed to allow bookmarking
console.log(`First injected address: ${firstAddress}`);
// change url to contain address to allow bookmarking
router.push({
query: { seed: privateKeyHex },
query: { address: firstAddress },
});
accountStore.setAccount(newAccount);
accountStore.setAccount(firstAddress);
openNewWalletOverlay();
});

// console.log("no seed found in url. will automatically create fresh wallet");
// cryptoWaitReady().then(() => {
// const generatedMnemonic = mnemonicGenerate();
// const localKeyring = new Keyring({ type: "sr25519", ss58Format: 42 });
// const newAccount = localKeyring.addFromMnemonic(generatedMnemonic, {
// name: "fresh",
// });
// const seed = mnemonicToMiniSecret(generatedMnemonic);
// const privateKeyHex = u8aToHex(seed);
// console.log(`Private Key in Hex: ${privateKeyHex}`);
// // change url to contain new seed to allow bookmarking
// router.push({
// query: { seed: privateKeyHex },
// });
// accountStore.setAccount(newAccount);
// openNewWalletOverlay();
// });
}
});

Expand Down
22 changes: 17 additions & 5 deletions store/account.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { defineStore } from "pinia";
import type { KeyringPair } from "@polkadot/keyring/types";
import { formatBalance } from "@polkadot/util";
import type {AddressOrPair} from "@polkadot/api-base/types";
import { asString } from "@encointer/util"
import type {InjectedExtension} from "@polkadot/extension-inject/types";

formatBalance.setDefaults({
decimals: 10,
unit: "",
});
export const useAccount = defineStore("account", {
state: () => ({
account: <KeyringPair | null>null,
account: <AddressOrPair | null>null,
injector: <InjectedExtension |null>null,
paseoBalance: 0,
incogniteeBalance: 0,
}),
getters: {
getShortAddress({ account }): string {
return account ? account.address.slice(0, 8) + "..." : "none";
return account ? asString(account as AddressOrPair).slice(0, 8) + "..." : "none";
},
getAddress({ account }): string {
return account ? account.address : "none";
return account ? asString(account as AddressOrPair) : "none";
},
hasInjector({ injector }): boolean {
return injector != null;
},
getIncogniteeHumanBalance({ incogniteeBalance }): number {
return formatBalance(incogniteeBalance);
Expand All @@ -27,9 +33,15 @@ export const useAccount = defineStore("account", {
},
},
actions: {
setAccount(account: KeyringPair) {
setAccount(account: AddressOrPair) {
this.account = account;
},
setInjector(injector: InjectedExtension) {
this.injector = injector;
},
setPaseoBalance(balance: number) {
this.paseoBalance = balance;
},
setIncogniteeBalance(balance: number) {
this.incogniteeBalance = balance;
},
Expand Down
Loading
Loading