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

3.0.0: Refactor Transaction class #854

Merged
merged 17 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from 15 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 .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2.1
orbs:
node: circleci/[email protected]
slack: circleci/[email protected]
browser-tools: circleci/[email protected].3
browser-tools: circleci/[email protected].6
gh-pages: sugarshin/[email protected]

parameters:
Expand Down Expand Up @@ -89,7 +89,8 @@ jobs:
$(lsb_release -cs) stable" | $SUDO tee /etc/apt/sources.list.d/docker.list > /dev/null
$SUDO apt update
$SUDO apt -y install docker-ce docker-ce-cli containerd.io
- browser-tools/install-browser-tools
- browser-tools/install-browser-tools:
replace-existing-chrome: true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures we always get the latest stable chrome version, which our browser testing relies on

Copy link
Contributor

@gmalouf gmalouf Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to intentionally test on a cross-range of versions? Wondering if instead of doing latest, we should do latest, plus X releases back.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be some value in selecting an older chrome version to test against, so that we can be sure the code isn't relying on APIs/behaviors that we think are too new.

But in reality it's easiest to test against latest and we still benefit a lot from having this.

I only included this change because for some reason circle stopped installing the latest chrome by default, which broke our test

- run:
name: << parameters.browser >> test
command: |
Expand Down
10 changes: 5 additions & 5 deletions examples/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async function main() {
const mnemonic =
'creek phrase island true then hope employ veteran rapid hurdle above liberty tissue connect alcohol timber idle ten frog bulb embody crunch taxi abstract month';
const recoveredAccount = algosdk.mnemonicToSecretKey(mnemonic);
console.log('Recovered mnemonic account: ', recoveredAccount.addr);
console.log('Recovered mnemonic account: ', recoveredAccount.addr.toString());
// example: ACCOUNT_RECOVER_MNEMONIC

const funder = accounts[0];
Expand All @@ -31,14 +31,14 @@ async function main() {
signerAccounts.push(algosdk.generateAccount());

// multiSigParams is used when creating the address and when signing transactions
const multiSigParams = {
const multiSigParams: algosdk.MultisigMetadata = {
version: 1,
threshold: 2,
addrs: signerAccounts.map((a) => a.addr),
};
const multisigAddr = algosdk.multisigAddress(multiSigParams);

console.log('Created MultiSig Address: ', multisigAddr);
console.log('Created MultiSig Address: ', multisigAddr.toString());
// example: MULTISIG_CREATE

const fundMsigTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
Expand Down Expand Up @@ -80,7 +80,7 @@ async function main() {
// example: ACCOUNT_GENERATE
const generatedAccount = algosdk.generateAccount();
const passphrase = algosdk.secretKeyToMnemonic(generatedAccount.sk);
console.log(`My address: ${generatedAccount.addr}`);
console.log(`My address: ${generatedAccount.addr.toString()}`);
console.log(`My passphrase: ${passphrase}`);
// example: ACCOUNT_GENERATE

Expand Down Expand Up @@ -117,7 +117,7 @@ async function main() {
rekeyTo: acct1.addr,
});
await client.sendRawTransaction(rekeyBack.signTxn(acct2.privateKey)).do();
await algosdk.waitForConfirmation(client, rekeyBack.txID().toString(), 3);
await algosdk.waitForConfirmation(client, rekeyBack.txID(), 3);
}

main();
4 changes: 2 additions & 2 deletions examples/asa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ async function main() {
sender: manager.addr,
suggestedParams,
assetIndex,
// assetFrozen: false would unfreeze the account's asset holding
assetFrozen: true,
// frozen: false would unfreeze the account's asset holding
frozen: true,
// freezeTarget is the account that is being frozen or unfrozen
freezeTarget: receiver.addr,
});
Expand Down
5 changes: 2 additions & 3 deletions examples/atomics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@ async function main() {
// example: ATOMIC_GROUP_SEND

// example: CONST_MIN_FEE
const minFee = algosdk.ALGORAND_MIN_TX_FEE;
console.log(minFee);
// This SDK does not expose a constant for the minimum fee
// example: CONST_MIN_FEE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove the comment references to CONST_MIN_FEE entirely? Also, there seems to be two identical lines for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are used to populate snippets of code in the dev site. This specific one is used here: https://developer.algorand.org/docs/get-details/dapps/smart-contracts/guidelines/#get-minimum-fee-off-chain-with-sdk

I think we want to preserve JS in that tab, but just have a comment saying a hard coded min fee is not available. That's currently what happens for the "using an algod API" JS snippet on that page


// example: TRANSACTION_FEE_OVERRIDE
const sp = await client.getTransactionParams().do();
sp.fee = 2 * minFee;
sp.fee = BigInt(2) * sp.minFee;
sp.flatFee = true;
// example: TRANSACTION_FEE_OVERRIDE

Expand Down
3 changes: 1 addition & 2 deletions examples/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ async function main() {

// example: CODEC_ADDRESS
const address = '4H5UNRBJ2Q6JENAXQ6HNTGKLKINP4J4VTQBEPK5F3I6RDICMZBPGNH6KD4';
const pk = algosdk.decodeAddress(address);
const addr = algosdk.encodeAddress(pk.publicKey);
const addr = algosdk.Address.fromString(address);
console.log(address, addr);
// example: CODEC_ADDRESS

Expand Down
2 changes: 1 addition & 1 deletion examples/kmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async function main() {

// example: KMD_IMPORT_ACCOUNT
const newAccount = algosdk.generateAccount();
console.log('Account: ', newAccount.addr);
console.log('Account: ', newAccount.addr.toString());
const importedAccount = await kmdClient.importKey(
wallethandle,
newAccount.sk
Expand Down
19 changes: 12 additions & 7 deletions examples/participation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,23 @@ async function main() {
// Parent addr
const addr = 'MWAPNXBDFFD2V5KWXAHWKBO7FO4JN36VR4CIBDKDDE7WAUAGZIXM3QPJW4';
// VRF public key
const selectionKey = 'LrpLhvzr+QpN/bivh6IPpOaKGbGzTTB5lJtVfixmmgk=';
const selectionKey = algosdk.base64ToBytes(
'LrpLhvzr+QpN/bivh6IPpOaKGbGzTTB5lJtVfixmmgk='
);
// Voting pub key
const voteKey = 'G/lqTV6MKspW6J8wH2d8ZliZ5XZVZsruqSBJMwLwlmo=';
const voteKey = algosdk.base64ToBytes(
'G/lqTV6MKspW6J8wH2d8ZliZ5XZVZsruqSBJMwLwlmo='
);
// State proof key
const stateProofKey =
'RpUpNWfZMjZ1zOOjv3MF2tjO714jsBt0GKnNsw0ihJ4HSZwci+d9zvUi3i67LwFUJgjQ5Dz4zZgHgGduElnmSA==';
const stateProofKey = algosdk.base64ToBytes(
'RpUpNWfZMjZ1zOOjv3MF2tjO714jsBt0GKnNsw0ihJ4HSZwci+d9zvUi3i67LwFUJgjQ5Dz4zZgHgGduElnmSA=='
);

// sets up keys for 100000 rounds
const numRounds = 1e5;
// sets up keys for 100,000 rounds
const numRounds = BigInt(100_000);

// dilution default is sqrt num rounds
const keyDilution = numRounds ** 0.5;
const keyDilution = BigInt(Math.floor(Math.sqrt(Number(numRounds))));

// create transaction
const onlineKeyreg =
Expand Down
6 changes: 3 additions & 3 deletions examples/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function getLocalAlgodClient() {
}

export interface SandboxAccount {
addr: string;
addr: algosdk.Address;
privateKey: Uint8Array;
signer: algosdk.TransactionSigner;
}
Expand Down Expand Up @@ -81,8 +81,8 @@ export async function getLocalAccounts(): Promise<SandboxAccount[]> {
kmdClient.releaseWalletHandle(handle);

return keys.map((k) => {
const addr = algosdk.encodeAddress(k.private_key.slice(32));
const acct = { sk: k.private_key, addr } as algosdk.Account;
const addr = new algosdk.Address(k.private_key.slice(32));
const acct: algosdk.Account = { sk: k.private_key, addr };
const signer = algosdk.makeBasicAccountTransactionSigner(acct);

return {
Expand Down
6 changes: 3 additions & 3 deletions src/account.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as nacl from './nacl/naclWrappers.js';
import * as address from './encoding/address.js';
import { Address } from './encoding/address.js';
import Account from './types/account.js';

/**
* generateAccount returns a new Algorand address and its corresponding secret key
*/
export default function generateAccount(): Account {
const keys = nacl.keyPair();
const encodedPk = address.encodeAddress(keys.publicKey);
return { addr: encodedPk, sk: keys.secretKey };
const addr = new Address(keys.publicKey);
return { addr, sk: keys.secretKey };
}
93 changes: 0 additions & 93 deletions src/bid.ts

This file was deleted.

39 changes: 23 additions & 16 deletions src/boxStorage.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { EncodedBoxReference } from './types/index.js';
import { EncodedBoxReference } from './types/transactions/index.js';
import { BoxReference } from './types/transactions/base.js';

function translateBoxReference(
reference: BoxReference,
foreignApps: number[],
appIndex: number
foreignApps: bigint[],
appIndex: bigint
): EncodedBoxReference {
const referenceId = reference.appIndex;
const referenceId = BigInt(reference.appIndex);
const referenceName = reference.name;
const isOwnReference = referenceId === 0 || referenceId === appIndex;
let index = 0;
const isOwnReference = referenceId === BigInt(0) || referenceId === appIndex;

// Foreign apps start from index 1; index 0 is its own app ID.
const index = foreignApps.indexOf(referenceId) + 1;

if (foreignApps != null) {
// Foreign apps start from index 1; index 0 is its own app ID.
index = foreignApps.indexOf(referenceId) + 1;
}
// Check if the app referenced is itself after checking the foreign apps array.
// If index is zero, then the app ID was not found in the foreign apps array
// or the foreign apps array was null.
Expand All @@ -23,20 +21,29 @@ function translateBoxReference(
// its own foreign apps array.
throw new Error(`Box ref with appId ${referenceId} not in foreign-apps`);
}
return { i: index, n: referenceName };

const encodedReference: EncodedBoxReference = {};
if (index !== 0) {
encodedReference.i = index;
}
if (referenceName.length) {
encodedReference.n = referenceName;
}
return encodedReference;
}

/**
* translateBoxReferences translates an array of BoxReferences with app IDs
* into an array of EncodedBoxReferences with foreign indices.
*/
export function translateBoxReferences(
references: BoxReference[] | undefined,
foreignApps: number[],
appIndex: number
references: ReadonlyArray<BoxReference>,
foreignApps: ReadonlyArray<number | bigint>,
appIndex: number | bigint
): EncodedBoxReference[] {
if (references == null) return [];
const appIndexBigInt = BigInt(appIndex);
const foreignAppsBigInt = foreignApps.map(BigInt);
return references.map((bx) =>
translateBoxReference(bx, foreignApps, appIndex)
translateBoxReference(bx, foreignAppsBigInt, appIndexBigInt)
);
}
18 changes: 7 additions & 11 deletions src/client/kmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
bytesToBase64,
coerceToBytes,
} from '../encoding/binarydata.js';
import * as txn from '../transaction.js';
import { Transaction } from '../transaction.js';
import { CustomTokenHeader, KMDTokenHeader } from './urlTokenBaseHTTPClient.js';
import ServiceClient from './v2/serviceClient.js';

Expand Down Expand Up @@ -260,14 +260,12 @@ export class KmdClient extends ServiceClient {
async signTransaction(
walletHandle: string,
walletPassword: string,
transaction: txn.TransactionLike
transaction: Transaction
) {
const tx = txn.instantiateTxnIfNeeded(transaction);

const req = {
wallet_handle_token: walletHandle,
wallet_password: walletPassword,
transaction: bytesToBase64(tx.toByte()),
transaction: bytesToBase64(transaction.toByte()),
};
const res = await this.c.post('/v1/transaction/sign', req);

Expand All @@ -290,16 +288,15 @@ export class KmdClient extends ServiceClient {
async signTransactionWithSpecificPublicKey(
walletHandle: string,
walletPassword: string,
transaction: txn.TransactionLike,
transaction: Transaction,
publicKey: Uint8Array | string
) {
const tx = txn.instantiateTxnIfNeeded(transaction);
const pk = coerceToBytes(publicKey);

const req = {
wallet_handle_token: walletHandle,
wallet_password: walletPassword,
transaction: bytesToBase64(tx.toByte()),
transaction: bytesToBase64(transaction.toByte()),
public_key: bytesToBase64(pk),
};
const res = await this.c.post('/v1/transaction/sign', req);
Expand Down Expand Up @@ -386,15 +383,14 @@ export class KmdClient extends ServiceClient {
async signMultisigTransaction(
walletHandle: string,
pw: string,
transaction: txn.TransactionLike,
transaction: Transaction,
pk: Uint8Array | string,
partial: string
) {
const tx = txn.instantiateTxnIfNeeded(transaction);
const pubkey = coerceToBytes(pk);
const req = {
wallet_handle_token: walletHandle,
transaction: bytesToBase64(tx.toByte()),
transaction: bytesToBase64(transaction.toByte()),
public_key: bytesToBase64(pubkey),
partial_multisig: partial,
wallet_password: pw,
Expand Down
Loading