Skip to content

Commit

Permalink
v1.0.5 (#27)
Browse files Browse the repository at this point in the history
* Fix the `signer` method so that it accepts both signed and unsigned transactions.
* Add the `indexesToSign` option to `signTransactions` to optionally specify which indexes of the group should be signed
* Add the `returnGroup` parameter to `signTransactions` to specify if all transactions that were passed should be returned, or just the ones signed by the provider.
  • Loading branch information
gabrielkuettel authored Dec 30, 2022
1 parent a5e853a commit 509fae7
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 61 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"url": "https://github.com/txnlab/use-wallet/issues"
},
"homepage": "https://txnlab.github.io/use-wallet",
"version": "1.0.4",
"version": "1.0.5",
"description": "React hooks for using Algorand compatible wallets in dApps.",
"scripts": {
"dev": "yarn storybook",
Expand Down
35 changes: 29 additions & 6 deletions src/clients/algosigner/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ class AlgoSignerClient extends BaseWallet {

async signTransactions(
connectedAccounts: string[],
transactions: Uint8Array[]
transactions: Uint8Array[],
indexesToSign?: number[],
returnGroup = true
) {
// Decode the transactions to access their properties.
const decodedTxns = transactions.map((txn) => {
Expand All @@ -143,16 +145,36 @@ class AlgoSignerClient extends BaseWallet {
// and add the signers property if they shouldn't be signed.
const txnsToSign = decodedTxns.reduce<AlgoSignerTransaction[]>(
(acc, txn, i) => {
const isSigned = "txn" in txn;

const txnObj: AlgoSignerTransaction = {
txn: this.#client.encoding.msgpackToBase64(transactions[i]),
};

if (
"txn" in txn ||
!connectedAccounts.includes(this.algosdk.encodeAddress(txn["snd"]))
indexesToSign &&
indexesToSign.length &&
!indexesToSign.includes(i)
) {
txnObj.txn = this.#client.encoding.msgpackToBase64(
isSigned
? this.algosdk
.decodeSignedTransaction(transactions[i])
.txn.toByte()
: this.algosdk.decodeUnsignedTransaction(transactions[i]).toByte()
);
txnObj.signers = [];
} else if (
!connectedAccounts.includes(
this.algosdk.encodeAddress(isSigned ? txn.txn["snd"] : txn["snd"])
)
) {
txnObj.txn = this.#client.encoding.msgpackToBase64(
this.algosdk.decodeSignedTransaction(transactions[i]).txn.toByte()
isSigned
? this.algosdk
.decodeSignedTransaction(transactions[i])
.txn.toByte()
: this.algosdk.decodeUnsignedTransaction(transactions[i]).toByte()
);
txnObj.signers = [];
}
Expand All @@ -167,11 +189,12 @@ class AlgoSignerClient extends BaseWallet {
// Sign them with the client.
const result = await this.#client.signTxn(txnsToSign);

// Join the newly signed transactions with the original group of transactions.
// Join the newly signed transactions with the original group of transactions
// if 'returnGroup' param is specified
const signedTxns = result.reduce<Uint8Array[]>((acc, txn, i) => {
if (txn) {
acc.push(new Uint8Array(Buffer.from(txn.blob, "base64")));
} else {
} else if (returnGroup) {
acc.push(transactions[i]);
}

Expand Down
4 changes: 3 additions & 1 deletion src/clients/base/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ abstract class BaseClient {
abstract reconnect(onDisconnect: () => void): Promise<Wallet | null>;
abstract signTransactions(
connectedAccounts: string[],
transactions: Array<Uint8Array>
transactions: Array<Uint8Array>,
indexesToSign?: number[],
returnGroup?: boolean
): Promise<Uint8Array[]>;
abstract signEncodedTransactions(
transactions: TransactionsArray
Expand Down
38 changes: 30 additions & 8 deletions src/clients/defly/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,28 +122,49 @@ class DeflyWalletClient extends BaseWallet {

async signTransactions(
connectedAccounts: string[],
transactions: Uint8Array[]
transactions: Uint8Array[],
indexesToSign?: number[],
returnGroup = true
) {
// Decode the transactions to access their properties.
const decodedTxns = transactions.map((txn) => {
return this.algosdk.decodeObj(txn);
}) as Array<DecodedTransaction | DecodedSignedTransaction>;

const signedIndexes: number[] = [];

// Marshal the transactions,
// and add the signers property if they shouldn't be signed.
const txnsToSign = decodedTxns.reduce<DeflyTransaction[]>((acc, txn, i) => {
if (
!("txn" in txn) &&
const isSigned = "txn" in txn;

// If the indexes to be signed is specified, designate that it should be signed
if (indexesToSign && indexesToSign.length && indexesToSign.includes(i)) {
signedIndexes.push(i);
acc.push({
txn: this.algosdk.decodeUnsignedTransaction(transactions[i]),
});
// If the transaction is unsigned and is to be sent from a connected account,
// designate that it should be signed
} else if (
!isSigned &&
connectedAccounts.includes(this.algosdk.encodeAddress(txn["snd"]))
) {
signedIndexes.push(i);
acc.push({
txn: this.algosdk.decodeUnsignedTransaction(transactions[i]),
});
} else {
// Otherwise, designate that it should not be signed
} else if (isSigned) {
acc.push({
txn: this.algosdk.decodeSignedTransaction(transactions[i]).txn,
signers: [],
});
} else if (!isSigned) {
acc.push({
txn: this.algosdk.decodeUnsignedTransaction(transactions[i]),
signers: [],
});
}

return acc;
Expand All @@ -152,12 +173,13 @@ class DeflyWalletClient extends BaseWallet {
// Sign them with the client.
const result = await this.#client.signTransaction([txnsToSign]);

// Join the newly signed transactions with the original group of transactions.
const signedTxns = decodedTxns.reduce<Uint8Array[]>((acc, txn, i) => {
if (!("txn" in txn)) {
// Join the newly signed transactions with the original group of transactions
// if 'returnGroup' param is specified
const signedTxns = transactions.reduce<Uint8Array[]>((acc, txn, i) => {
if (signedIndexes.includes(i)) {
const signedByUser = result.shift();
signedByUser && acc.push(signedByUser);
} else {
} else if (returnGroup) {
acc.push(transactions[i]);
}

Expand Down
26 changes: 19 additions & 7 deletions src/clients/exodus/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,33 @@ class ExodusClient extends BaseWallet {

async signTransactions(
connectedAccounts: string[],
transactions: Array<Uint8Array>
transactions: Array<Uint8Array>,
indexesToSign?: number[],
returnGroup = true
) {
// Decode the transactions to access their properties.
const decodedTxns = transactions.map((txn) => {
return this.algosdk.decodeObj(txn);
}) as Array<DecodedTransaction | DecodedSignedTransaction>;

const signedIndexes: number[] = [];

// Get the unsigned transactions.
const txnsToSign = decodedTxns.reduce<Uint8Array[]>((acc, txn, i) => {
// If the transaction isn't already signed and is to be sent from a connected account,
const isSigned = "txn" in txn;

// If the indexes to be signed is specified
// add it to the arrays of transactions to be signed.
if (
!("txn" in txn) &&
if (indexesToSign && indexesToSign.length && indexesToSign.includes(i)) {
signedIndexes.push(i);
acc.push(transactions[i]);
// If the transaction isn't already signed and is to be sent from a connected account,
// add it to the arrays of transactions to be signed
} else if (
!isSigned &&
connectedAccounts.includes(this.algosdk.encodeAddress(txn["snd"]))
) {
signedIndexes.push(i);
acc.push(transactions[i]);
}

Expand All @@ -146,11 +158,11 @@ class ExodusClient extends BaseWallet {
const result = await this.#client.signTransaction(txnsToSign);

// Join the newly signed transactions with the original group of transactions.
const signedTxns = decodedTxns.reduce<Uint8Array[]>((acc, txn, i) => {
if (!("txn" in txn)) {
const signedTxns = transactions.reduce<Uint8Array[]>((acc, txn, i) => {
if (signedIndexes.includes(i)) {
const signedByUser = result.shift();
signedByUser && acc.push(signedByUser);
} else {
} else if (returnGroup) {
acc.push(transactions[i]);
}

Expand Down
40 changes: 31 additions & 9 deletions src/clients/kmd/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ class KMDWalletClient extends BaseWallet {

async signTransactions(
connectedAccounts: string[],
transactions: Uint8Array[]
transactions: Uint8Array[],
indexesToSign?: number[],
returnGroup = true
) {
// Decode the transactions to access their properties.
const decodedTxns = transactions.map((txn) => {
Expand All @@ -174,20 +176,34 @@ class KMDWalletClient extends BaseWallet {
const pw = await this.requestPassword();
const token = await this.getWalletToken(this.walletId, pw);

const signedTxns: Uint8Array[] = [];
const signedTxns: Array<Uint8Array> = [];
// Sign them with the client.
const signingPromises: Promise<Uint8Array>[] = [];

for (const idx in decodedTxns) {
const dtxn = decodedTxns[idx];
const isSigned = "txn" in dtxn;

// push the incoming txn into signed, we'll overwrite it later
signedTxns.push(transactions[idx]);

// Its already signed, skip it
if (!("snd" in dtxn)) continue;
if (isSigned) {
continue;
// Not specified in indexes to sign, skip it
} else if (
indexesToSign &&
indexesToSign.length &&
!indexesToSign.includes(Number(idx))
) {
continue;
}
// Not to be signed by our signer, skip it
if (!connectedAccounts.includes(this.algosdk.encodeAddress(dtxn.snd)))
else if (
!connectedAccounts.includes(this.algosdk.encodeAddress(dtxn.snd))
) {
continue;
}

// overwrite with an empty blob
signedTxns[idx] = new Uint8Array();
Expand All @@ -200,16 +216,22 @@ class KMDWalletClient extends BaseWallet {

// Restore the newly signed txns in the correct order
let signedIdx = 0;
for (const idx in signedTxns) {

const formattedTxns = signedTxns.reduce<Uint8Array[]>((acc, txn, i) => {
// If its an empty array, infer that it is one of the
// ones we wanted to have signed and overwrite the empty buff
if (signedTxns[idx].length === 0) {
signedTxns[idx] = signingResults[signedIdx];
if (txn.length === 0) {
acc.push(signingResults[signedIdx]);

signedIdx += 1;
} else if (returnGroup) {
acc.push(txn);
}
}

return signedTxns;
return acc;
}, []);

return formattedTxns;
}

signEncodedTransactions(
Expand Down
31 changes: 20 additions & 11 deletions src/clients/myalgo/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,32 @@ class MyAlgoWalletClient extends BaseWallet {

async signTransactions(
connectedAccounts: string[],
transactions: Uint8Array[]
transactions: Uint8Array[],
indexesToSign?: number[],
returnGroup = true
) {
// Decode the transactions to access their properties.
const decodedTxns = transactions.map((txn) => {
return this.algosdk.decodeObj(txn);
}) as Array<DecodedTransaction | DecodedSignedTransaction>;

// Get the unsigned transactions.
const signedIndexes: number[] = [];

// Get the transactions to be signed
const txnsToSign = decodedTxns.reduce<Uint8Array[]>((acc, txn, i) => {
// If the transaction isn't already signed and is to be sent from a connected account,
// add it to the arrays of transactions to be signed.
const isSigned = "txn" in txn;

if (
!("txn" in txn) &&
// If the indexes to be signed is specified, add it to the transactions to be signed,
if (indexesToSign && indexesToSign.length && indexesToSign?.includes(i)) {
signedIndexes.push(i);
acc.push(transactions[i]);
// Otherwise, if the transaction is unsigned and is to be sent from a connected account,
// add it to the transactions to be signed
} else if (
!isSigned &&
connectedAccounts.includes(this.algosdk.encodeAddress(txn["snd"]))
) {
signedIndexes.push(i);
acc.push(transactions[i]);
}

Expand All @@ -126,13 +136,12 @@ class MyAlgoWalletClient extends BaseWallet {
// Sign them with the client.
const result = await this.#client.signTransaction(txnsToSign);

// Join the newly signed transactions with the original group of transactions.
const signedTxns = decodedTxns.reduce<Uint8Array[]>((acc, txn, i) => {
if (!("txn" in txn)) {
const signedTxns = transactions.reduce<Uint8Array[]>((acc, txn, i) => {
if (signedIndexes.includes(i)) {
const signedByUser = result.shift()?.blob;
signedByUser && acc.push(signedByUser);
} else {
acc.push(transactions[i]);
} else if (returnGroup) {
acc.push(txn);
}

return acc;
Expand Down
Loading

0 comments on commit 509fae7

Please sign in to comment.