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

Implement Wallet-Based Authentication with Stellar Wallet Kit #20

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@
"uuid": "^9.0.0",
"vite": "^4.5.5"
},
"type": "module"
"type": "module",
"dependencies": {
"@creit.tech/stellar-wallets-kit": "^1.2.1"
josephchimebuka marked this conversation as resolved.
Show resolved Hide resolved
}
}
42 changes: 42 additions & 0 deletions src/lib/components/WalletKitProvider.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!-- src/lib/components/WalletComponent.svelte -->
<script>
import { goto } from '$app/navigation';
import { walletStore } from '$lib/stores/walletStore';
// @ts-ignore
import { StellarWalletsKit, WalletNetwork, allowAllModules, XBULL_ID } from '@creit.tech/stellar-wallets-kit'



export let buttonText = 'Connect Wallet';
const kit = new StellarWalletsKit({
network: WalletNetwork.TESTNET,
selectedWalletId: XBULL_ID,
modules: allowAllModules(),
});

const connectWallet = async () => {
try {
await kit.openModal({
// @ts-ignore
onWalletSelected: async (option) => {
kit.setWallet(option.id);
const { address } = await kit.getAddress();

if (address) {
await walletStore.registerWithWallet({ publicKey: address });
goto('/dashboard');
}
}
});
} catch (error) {
console.error('Error connecting wallet:', error);
}
};

export { connectWallet };
</script>

<!-- You can provide a button or any UI elements if needed -->
<button type="button" class="btn-secondary btn" on:click={connectWallet}>
{buttonText}
</button>
85 changes: 74 additions & 11 deletions src/lib/stores/walletStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { get } from 'svelte/store'
import { persisted } from 'svelte-local-storage-store'
import { KeyManager, KeyManagerPlugins, KeyType } from '@stellar/wallet-sdk'
import { TransactionBuilder } from 'stellar-sdk'
import {
StellarWalletsKit,
WalletNetwork,
allowAllModules,
XBULL_ID
} from '@creit.tech/stellar-wallets-kit';


/** @typedef {import('stellar-sdk').Transaction} Transaction */

Expand All @@ -16,11 +23,42 @@ import { TransactionBuilder } from 'stellar-sdk'

function createWalletStore() {
/** @type {import('svelte/store').Writable<WalletStore>} */
const { subscribe, set } = persisted('bpa:walletStore', { keyId: '', publicKey: '' })

const { subscribe, set, } = persisted('bpa:walletStore', { keyId: '', publicKey: '' })
return {
subscribe,



/**
* Registers a user by their public key (wallet-based registration)
* @param {Object} opts Options object
* @param {string} opts.publicKey Public Stellar address
*/
registerWithWallet: async ({ publicKey }) => {
try {
set({
keyId: publicKey, // Using publicKey as keyId for simplicity
publicKey: publicKey,
})
} catch (err) {
console.error('Error registering wallet', err)
// throw new Error(err.toString())
}
},

/**
* Logs in a user by their public key (wallet-based login)
* @param {string} publicKey Public Stellar address
*/
loginWithWallet: async (publicKey) => {
const storeValue = get(walletStore);
if (storeValue.publicKey !== publicKey) {
throw error(400, { message: 'Wallet not registered' });
}
// If the publicKey matches, the user is considered logged in.
// You might want to add additional logic here if needed.
},

/**
* Registers a user by storing their encrypted keypair in the browser's localStorage.
* @param {Object} opts Options object
Expand Down Expand Up @@ -57,7 +95,7 @@ function createWalletStore() {
console.error('Error saving key', err)
// @ts-ignore
throw error(400, { message: err.toString() })
}
}
},

/**
Expand Down Expand Up @@ -95,19 +133,44 @@ function createWalletStore() {
*/
sign: async ({ transactionXDR, network, pincode }) => {
try {
const keyManager = setupKeyManager()
let signedTransaction = await keyManager.signTransaction({

const { keyId, publicKey } = get(walletStore);

if (keyId === publicKey) {
const kit = new StellarWalletsKit({
network: WalletNetwork.TESTNET,
josephchimebuka marked this conversation as resolved.
Show resolved Hide resolved
selectedWalletId: XBULL_ID,
modules: allowAllModules(),
});
const { address } = await kit.getAddress();

// Sign the transaction using the wallet address
const { signedTxXdr } = await kit.signTransaction(transactionXDR, {
address,
networkPassphrase: network, // or use your specific network passphrase
});

// @ts-ignore
transaction: TransactionBuilder.fromXDR(transactionXDR, network),
id: get(walletStore).keyId,
password: pincode,
})
return signedTransaction
} catch (err) {
return signedTxXdr; // Return the signed transaction
} else {

const keyManager = setupKeyManager();
// Fallback to signing with pincode if no wallet
const signedTransaction = await keyManager.signTransaction({
// @ts-ignore
transaction: TransactionBuilder.fromXDR(transactionXDR, network),
id: keyId,
password: pincode,
});
// @ts-ignore
return signedTransaction;
}
}catch (err) {
console.error('Error signing transaction', err)
// @ts-ignore
throw error(400, { message: err.toString() })
}

},
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/routes/dashboard/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import Navbar from './components/Navbar.svelte'
import Drawer from './components/Drawer.svelte'
import Footer from './components/Footer.svelte'
</script>
</script>

<div class="flex min-h-screen flex-col">
<Navbar />
Expand Down
13 changes: 12 additions & 1 deletion src/routes/login/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,16 @@ for submission to the network.
import { goto } from '$app/navigation'
import { errorMessage } from '$lib/stores/alertsStore'
import { walletStore } from '$lib/stores/walletStore'

import WalletKitProvider from '$lib/components/WalletKitProvider.svelte'
// Define some component variables that will be used throughout the page
let pincode = ''







/**
* Our `login` function ensures the the user has entered a valid pincode for the encrypted keypair, and then redirects them to the dashboard page.
* @async
Expand Down Expand Up @@ -86,6 +92,11 @@ for submission to the network.
<div class="form-control mt-6">
<button class="btn-primary btn">Login</button>
</div>


<div class="form-control mt-2">
<WalletKitProvider buttonText='Login with wallet'/>
</div>
</form>
</div>
</div>
Expand Down
12 changes: 11 additions & 1 deletion src/routes/signup/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ circumstance.
import { goto } from '$app/navigation'
import { walletStore } from '$lib/stores/walletStore'
import { fundWithFriendbot } from '$lib/stellar/horizonQueries'

import WalletKitProvider from '$lib/components/WalletKitProvider.svelte'
// The `open` Svelte context is used to open the confirmation modal
import { getContext } from 'svelte'
const { open } = getContext('simple-modal')
Expand All @@ -40,6 +40,8 @@ circumstance.
let showSecret = false
let pincode = ''



/**
* Takes an action after the pincode has been confirmed by the user.
* @async
Expand Down Expand Up @@ -74,6 +76,11 @@ circumstance.
onConfirm: onConfirm,
})
}





</script>

<div class="hero min-h-screen bg-base-200">
Expand Down Expand Up @@ -147,6 +154,9 @@ circumstance.
<div class="form-control mt-6">
<button type="submit" class="btn-primary btn">Signup</button>
</div>
<div class="form-control mt-2">
<WalletKitProvider buttonText='Sign up with wallet'/>
</div>
<div class="form-control my-1">
<div class="label">
<a class="link-hover label-text-alt link" href="/login">
Expand Down
Loading