Skip to content

Commit

Permalink
Merge pull request #21 from Dartroom/20-incompatibility-with-logic-si…
Browse files Browse the repository at this point in the history
…gs-and-pera

Add support for logic sigs
  • Loading branch information
stefdegroot committed Jun 12, 2023
2 parents 554328e + 57c90ba commit 29ce517
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 67 deletions.
86 changes: 81 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,83 @@
A package that aggregates multiple Algorand signing options into one interface. Handles signing and address/login management.

Integrates the following services:
- AlgoSigner
- MyAlgo
- PeraWallet
- Exodus
Integrates the following wallet apps:
- [AlgoSigner](https://github.com/PureStake/algosigner)
- [MyAlgo](https://github.com/randlabs/myalgo-connect)
- [PeraWallet](https://github.com/perawallet/connect)

## Documenation
- [Installation](#installation)
- [Setup](#setup)
- [Options](#options)
- [Connect](#connect)
- [Sign transactions](#sign-transactions)

# Installation

```bash
npm install @dartroom/signer
```

# Setup

```ts
import { Wallet, Address } from '@dartroom/signer'

const wallet = new Wallet({
ledger: "MAINNET"
})
```

## Options

#### **`ledger?: "MAINNET" | "TESTNET"`**

Some wallet apps require the specification of the network to use. (instead of reading the genesis hash from the transactions them selfs)

# Connect

The Dartroom Signer does not have any UI built-in. All methods are designed to be integrated with your own UI.

When you want to connect to the users' wallet app, you first let them choose between the available options. `AlgoSigner`, `MyAlgo` and `PeraWallet` are currently supported. The chosen options can be passed into the `connectNewAddress`, triggering the wallet connection process.

```ts
const addresses = await wallet.connectNewAddress({ wallet: "PeraWallet" })
```

The return value is an array of one or more addresses, depending on how many the users selected.

```ts
type AddressList = Array<{
address: string
wallet: Wallets
}>
```
The package supports multiple connections to different wallet apps. The users can stay connected to all three supported wallets a the same time.
In cases where the users need to choose a single address, you can store this configuration with the `setActive` function. This function will store the configuration in the LocalStorage of the browser.
The active wallet setting does not affect the signing of transactions. You can always sign transactions for any connect address, regardless of if it is the chosen one.
```ts
wallet.setActive({
address: "FSQW3UTLB5IZ32ZE35MUDPNNAXHCBGMGAKXHR3ENQ5JMT43IB3BET7WPDE",
wallet: "PeraWallet"
})

console.log(wallet.active) // { address: "FSQW3UTLB5IZ32ZE35MUDPNNAXHCBGMGAKXHR3ENQ5JMT43IB3BET7WPDE", wallet: "PeraWallet" }
```

Algon side storing the active wallet, the connect accounts and sessions are also stored. When you create a new instance of the `Wallet` class, it will always try to restore the last session.

# Sign transactions

```ts
const signedTxns = await wallet.signTransactions([
[
{
blob: [],
signers: ["FSQW3UTLB5IZ32ZE35MUDPNNAXHCBGMGAKXHR3ENQ5JMT43IB3BET7WPDE"]
},
]
])
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dartroom/signer",
"version": "0.3.2-alpha",
"version": "0.3.3-alpha",
"description": "A package that aggregates multiple Algorand signing options into one interface. Handles signing and address/login management.",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
6 changes: 3 additions & 3 deletions src/algoSigner/connect.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Provider, Wallets } from '../main'
import { Provider, Address } from '../main'

export default async function connect ({ algoSigner, ledger }: Provider) {
export default async function connect ({ algoSigner, ledger }: Provider): Promise<Array<Address>> {

if (!algoSigner) {
throw new Error('Failed to connect with the AlgoSigner. Make sure the browser extension is installed.')
Expand All @@ -27,7 +27,7 @@ export default async function connect ({ algoSigner, ledger }: Provider) {
return accounts.map((a) => {
return {
address: a,
wallet: Wallets.ALGOSIGNER
wallet: "AlgoSigner"
}
})
} else {
Expand Down
21 changes: 17 additions & 4 deletions src/algoSigner/signTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default async function sign<T extends Txn>({ algoSigner }: Provider, txns
txn: algoSigner.algorand.encoding.msgpackToBase64(txn.blob),
} as AlgoSignerTxn

if (txn.authAddress) {
if (txn.authAddress && txn.signers.length !== 0) {
format['authAddr'] = txn.authAddress
} else if (txn.signers) {
format['signers'] = txn.signers
Expand All @@ -53,8 +53,17 @@ export default async function sign<T extends Txn>({ algoSigner }: Provider, txns
})

let formated: Array<Array<T>> = []

const signedTxns = await algoSigner.algorand.signTxns(formatedTxns) as unknown as Array<string>
let signedTxns: Array<string | null>

try {
signedTxns = await algoSigner.algorand.signTxns(formatedTxns) as unknown as Array<string>
} catch (e: any) {
if (e.data) {
throw new Error(e.data)
} else {
throw new Error(e)
}
}

if (signedTxns && signedTxns.length > 0) {
formated = txns.map((txnArray, i) => {
Expand All @@ -72,14 +81,18 @@ export default async function sign<T extends Txn>({ algoSigner }: Provider, txns
throw new Error('Failed to parse transaction array.')
}

if (!signedTxn) {
return usignedTxn
}

return {
...usignedTxn,
blob: Uint8Array.from(algoSigner.algorand.encoding.base64ToMsgpack(signedTxn))
}
})
})
} else {
throw new Error('')
throw new Error('Failed to parse transaction array.')
}

return formated
Expand Down
23 changes: 11 additions & 12 deletions src/connect.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Provider, Wallets, Addresses, Wallet } from './main'
import { Provider, Wallets, Addresses } from './main'

import connectMyAlgo from './myAlgo/connect'
import connectAlgoSigner from './algoSigner/connect'
import connectPera from './pera/connect'
import connectExodus from './exodus/connect'

export interface ConnectSettings {
wallet: Wallets
Expand All @@ -18,22 +17,22 @@ export default async function connect (provider: Provider, { wallet }: ConnectSe
let newAddresses: Addresses

switch (wallet) {
case Wallets.MYALGO:
case "MyAlgo":
newAddresses = await connectMyAlgo(provider)
clearWallet(provider, Wallets.MYALGO)
clearWallet(provider, "MyAlgo")
break
case Wallets.PERA:
case "PeraWallet":
newAddresses = await connectPera(provider)
clearWallet(provider, Wallets.PERA)
clearWallet(provider, "PeraWallet")
break
case Wallets.ALGOSIGNER:
case "AlgoSigner":
newAddresses = await connectAlgoSigner(provider)
clearWallet(provider, Wallets.ALGOSIGNER)
break
case Wallets.EXODUS:
newAddresses = await connectExodus(provider)
clearWallet(provider, Wallets.EXODUS)
clearWallet(provider, "AlgoSigner")
break
// case Wallets.EXODUS:
// newAddresses = await connectExodus(provider)
// clearWallet(provider, Wallets.EXODUS)
// break
}

provider.addresses.push(...newAddresses)
Expand Down
20 changes: 10 additions & 10 deletions src/disconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ function clearWallet(p: Provider, w: Wallets, address?: string) {
export default async function disconnect (provider: Provider, { wallet, address }: DisconnectSettings) {

switch (wallet) {
case Wallets.MYALGO:
clearWallet(provider, Wallets.MYALGO, address)
case "MyAlgo":
clearWallet(provider, "MyAlgo", address)
break
case Wallets.PERA:
case "PeraWallet":
await disconnectPera(provider)
clearWallet(provider, Wallets.PERA)
clearWallet(provider, "PeraWallet")
break
case Wallets.ALGOSIGNER:
clearWallet(provider, Wallets.ALGOSIGNER, address)
break
case Wallets.EXODUS:
await disconnectExodus(provider)
clearWallet(provider, Wallets.EXODUS)
case "AlgoSigner":
clearWallet(provider, "AlgoSigner", address)
break
// case Wallets.EXODUS:
// await disconnectExodus(provider)
// clearWallet(provider, Wallets.EXODUS)
// break
}

if (provider.active && address) {
Expand Down
4 changes: 2 additions & 2 deletions src/exodus/connect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Provider, Wallets } from '../main'
import { Provider, Address } from '../main'

export default async function connect ({ exodus }: Provider) {

Expand Down Expand Up @@ -27,7 +27,7 @@ export default async function connect ({ exodus }: Provider) {
if (accounts) {
return [{
address: accounts[0],
wallet: Wallets.EXODUS
wallet: "Exodus"
}]
} else {
throw new Error('Either the user shared no accounts, or Exodus did not return any.')
Expand Down
29 changes: 13 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@ import setActive, { ActiveSettings } from './active'

export type Ledgers = 'MAINNET' | 'TESTNET'

export enum Wallets {
MYALGO = 'MyAlgo',
PERA = 'PeraWallet',
ALGOSIGNER = 'AlgoSigner',
EXODUS = 'Exodus'
}
export const WalletList = ["MyAlgo", "PeraWallet", "AlgoSigner"] as const

export type Wallets = typeof WalletList[number]

export interface Address {
address: string
Expand Down Expand Up @@ -65,7 +62,7 @@ export class Wallet {
chainId: options?.ledger ? (options.ledger === 'TESTNET' ? 416002 : 416001) : 416001
})
this.algoSigner = this.setAlgoSigner()
this.exodus = this.setExodus()
// this.exodus = this.setExodus()
this.ledger = options?.ledger || 'MAINNET'
this.addresses = this.getLocalAccounts()
this.active = this.getActive()
Expand Down Expand Up @@ -127,17 +124,17 @@ export class Wallet {
}
}

private setExodus () {
try {
const exodusSigner = exodus.algorand
// private setExodus () {
// try {
// const exodusSigner = exodus.algorand

exodusSigner.on('disconnect', this.disconnectAddress({ wallet: Wallets.EXODUS }))
// exodusSigner.on('disconnect', this.disconnectAddress({ wallet: Wallets.EXODUS }))

return exodusSigner
} catch {
return undefined
}
}
// return exodusSigner
// } catch {
// return undefined
// }
// }

// Wallet Connect implementation
// private setPera () {
Expand Down
6 changes: 3 additions & 3 deletions src/myAlgo/connect.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Provider, Wallets } from '../main'
import { Provider, Wallets, Address } from '../main'
import MyAlgoConnect from '@randlabs/myalgo-connect'

export default async function connect ({ }: Provider) {
export default async function connect ({ }: Provider): Promise<Array<Address>> {
const myAlgo = new MyAlgoConnect()

const accounts = await myAlgo.connect({
Expand All @@ -13,7 +13,7 @@ export default async function connect ({ }: Provider) {
return accounts.map((a) => {
return {
address: a.address,
wallet: Wallets.MYALGO
wallet: "MyAlgo"
}
})
} else {
Expand Down
8 changes: 4 additions & 4 deletions src/pera/connect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Provider, Wallets, Pera } from '../main'
import { Provider, Wallets, Address } from '../main'

// async function awaitConnect (pera: Pera): Promise<Array<string>> {
// return new Promise((resolve) => {
Expand Down Expand Up @@ -32,7 +32,7 @@ function clearWallet(addresses: Provider['addresses'], w: Wallets, address?: str
}


export default async function connect ({ pera, addresses }: Provider) {
export default async function connect ({ pera, addresses }: Provider): Promise<Array<Address>> {

// handeld by disconnect event
// if (pera.isConnected) {
Expand Down Expand Up @@ -76,14 +76,14 @@ export default async function connect ({ pera, addresses }: Provider) {
// accounts = await awaitConnect(pera)

pera.connector?.on('disconnect', () => {
clearWallet(addresses, Wallets.PERA)
clearWallet(addresses, "PeraWallet")
})

if (accounts && accounts.length > 0) {
return accounts.map((address) => {
return {
address: address,
wallet: Wallets.PERA
wallet: "PeraWallet"
}
})
} else {
Expand Down
Loading

0 comments on commit 29ce517

Please sign in to comment.