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

feat: Deprecate transfer and asset modules #291

Merged
merged 18 commits into from
Aug 28, 2024
Merged

feat: Deprecate transfer and asset modules #291

merged 18 commits into from
Aug 28, 2024

Conversation

robdmoore
Copy link
Contributor

@robdmoore robdmoore commented Jun 17, 2024

Follows on from #287.

Breaking changes:

  • Renamed AlgokitComposer to AlgoKitComposer to match AlgoKit naming conventions
  • Collapsed the second object in algorand.send.type(params, executeOptions) to combine into params and make it easier to use based on devrel feedback
  • Order of algorand.account.rekeyed() parameters to be rekeyed(sender, signer) since it conceptually makes more sense (the sender is rekeyed so should come first)
  • All microAlgo return values from algorand.account.getInformation() now return an AlgoAmount, renamed amount to balance and round to validAsAtRound (which is now a bigint for broader consistency)
  • Renamed algorand.account.getAssetInformation to algorand.asset.getAccountInformation

Added:

  • Return value of algorand.send.assetCreate now includes { assetId: bigint }
  • Up to date documentation for rekeyAccount, AlgorandClient, asset, dispenser client, indexer, testing, transfer
  • Up to date documentation for how to refer to an Algo amount (Algo (not plural) in general and ALGO (not plural) when referring to a specific amount)
  • AssetManager class and algorand.asset.getById(), algorand.asset.bulkOptIn, and algorand.asset.bulkOptOut
  • indexer export off of @algorandfoundation/algokit-utils as the future home of all indexer methods
  • Added algorand.client.getTestNetDispenserFromEnvironment
  • Added algorand.account.assetBulkOptIn
  • Added algorand.account.assetBulkOptOut
  • Added algorand.account.ensureFunded
  • Added algorand.account.ensureFundedFromEnvironment
  • Added algorand.account.ensureFundedFromTestNetDispenserApi
  • Added algorand.account.rekeyAccount
  • Added algorand.send/transaction.assetOptOut
  • Added buildTransactions method to AlgoKitComposer so you can build transactions without needing to register a signer
  • Added .algo and .microAlgo methods/properties in place of the plural version for AlgoAmount to reflect the current guidance on how to represent Algo amounts, kept previous versions of those methods for now to avoid the breaking change

Deprecated the following in favour of AlgorandClient functionality:

  • algokit.createAsset
  • algokit.assetOptIn
  • algokit.assetOptOut
  • algokit.assetBulkOptIn
  • algokit.assetBulkOptOut
  • algokit.ensureFunded
  • algokit.transferAsset
  • algokit.rekeyAccount
  • algokit.transferAlgos

@robdmoore robdmoore requested review from joe-p and neilcampbell June 17, 2024 17:24
@@ -144,7 +150,26 @@ export function getAccountAddressAsString(addressEncodedInB64: string): string {
* @returns The account information
*/
export async function getAccountInformation(sender: string | SendTransactionFrom, algod: Algodv2): Promise<AccountInformation> {
return new AccountManager(new ClientManager({ algod })).getInformation(getSenderAddress(sender))
const account = AccountInformationModel.from_obj_for_encoding(await algod.accountInformation(getSenderAddress(sender)).do())
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Keeping backwards compatibility in the legacy method (made changes to this method in AccountManager to return better types (AlgoAmount rather than number).


// Up to date exports
export * from './amount'
export * from './config'
export * as indexer from './indexer-lookup'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the indexer methods are useful as-is. Per previous discussions we don't want to make them that easy to use given preference to discourage use of indexer. I figure exposing them through an indexer export off the / is a good way of exposing them without making for a noisy / import.


export async function generateTestAsset(client: Algodv2, sender: Account, total?: number) {
export async function generateTestAsset(algorand: AlgorandClient, sender: string, total?: number) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Internal method so it's a non-breaking change for the library.

@@ -0,0 +1,198 @@
import { describe, test } from '@jest/globals'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rename of asset.spec.ts with changes to use algorandClient

@@ -0,0 +1,378 @@
import { describe, test } from '@jest/globals'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rename of transfer.spec.ts with changes to use algorandClient

@@ -118,8 +135,13 @@ export class AlgorandClient {
return this._accountManager
}

/** Methods for interacting with assets. */
public get asset() {
return this._assetManager
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added new manager (assetManager). For now it's simple (single method), but over time it may grow in complexity.

Copy link
Contributor

Choose a reason for hiding this comment

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

Should the bulk functions go in the AssetManager?

@@ -134,19 +156,19 @@ export class AlgorandClient {
preLog?: (params: T, transaction: Transaction) => string
postLog?: (params: T, result: SendSingleTransactionResult) => string
},
): (params: T, config?: ExecuteParams) => Promise<SendSingleTransactionResult> {
return async (params, config) => {
): (params: T & ExecuteParams) => Promise<SendSingleTransactionResult> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Combining these together per devrel feedback

@joe-p
Copy link
Contributor

joe-p commented Jun 17, 2024

Haven't done a proper review yet, but not sure how I feel about algorand.send/transaction.rekey. On one hand it's nice to have such an important operation be so explicit. On the other hand, I'm worried it might give developers the incorrect impression that a rekey is a special transaction type.

@robdmoore
Copy link
Contributor Author

No different to opt-in/opt-out imo

@robdmoore
Copy link
Contributor Author

robdmoore commented Jun 17, 2024

Also allows for a really explicit approach to such a dangerous but useful operation with a minimal set of parameters with intellisense. we could illustrate in the method description that rekey can also be added to any other transaction by setting the optional rekeyTo value?

@joe-p
Copy link
Contributor

joe-p commented Jun 17, 2024

No different to opt-in/opt-out imo

To me the main difference is that there are no negative consequences of a developer thinking optin/out is a seperate tx type. With rekeys, however, if a developer thinks that rekey is a special transaction type and reads code somewhere with a payment transaction or appl, they might be oblivious to the fact that it's rekeying an account.

Essentially I'm nervous it might "train" developers to look for .rekey calls rather than rekeyTo fields

@robdmoore
Copy link
Contributor Author

Another option is to add it to account manager as a method.

@joe-p
Copy link
Contributor

joe-p commented Jun 17, 2024

Another option is to add it to account manager as a method.

Yeah I like that. Makes it more clear that it's abstraction and not a transaction type

@robdmoore
Copy link
Contributor Author

Cool, done.

Funnily enough it was how I originally wrote it, but then I decided to make it a composer thing so you could get the transaction separate to sending it. I think that's a minor benefit though.

@robdmoore robdmoore mentioned this pull request Jun 18, 2024
@joe-p
Copy link
Contributor

joe-p commented Jun 18, 2024

small nit: I would change rekeyAccount to rekeyAddress. In general as we start to get HD wallet support we should try to avoid using "account" to refer to a single address.

Copy link
Contributor

@joe-p joe-p left a comment

Choose a reason for hiding this comment

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

@robdmoore can you remind me why we decided to support a union of string | TransactionSignerAccount for address fields? When would the TransactionSignerAccount be useful? I think it might be a bit confusing especially when I was looking at account.rekeyed. I suppose it's not clear when I'd want to use this vs setting the signer for address.

Also, I see a lot of changes to the formatting of how we saw "Algos". Personally I think non-plural ALGO is the most common. Ie. "I have 10 ALGO" vs "I have 10 Algos"


// Note: if a signing account is passed into `algorand.account.rekeyAccount` then you don't need to call `rekeyedAccount` to register the new signer
const rekeyedAccount = algokit.rekeyedAccount(newAccount, account.addr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const rekeyedAccount = algokit.rekeyedAccount(newAccount, account.addr)
const rekeyedAccount = Algorand.account.rekeyed(newAccount, account.addr)

@@ -2,7 +2,7 @@

`AlgorandClient` is a client class that brokers easy access to Algorand functionality. It's the [default entrypoint](../README.md#usage) into AlgoKit Utils functionality.

The main entrypoint to the bulk of the functionality in AlgoKit Utils is the `AlgorandClient` class, most of the time you can get started by typing `algokit.AlgorandClient.` and choosing one of the static initialisation methods to create an [Algorand client](./capabilities/algorand-client.md), e.g.:
The main entrypoint to the bulk of the functionality in AlgoKit Utils is the `AlgorandClient` class, most of the time you can get started by typing `algokit.AlgorandClient.` and choosing one of the static initialisation methods to create an [Algorand client](../code/classes/types_algorand_client.AlgorandClient.md), e.g.:
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't we now recommending to import AlgorandClient directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep this needs to be fixed

const secondAccount = await generateAccount({
initialFunds: algokit.algos(1),
initialFunds: (1).algos(),
suppressLog: true,
})
const createParams = await getTestingAppCreateParams(testAccount, {
Copy link
Contributor

Choose a reason for hiding this comment

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

This line can be deleted

@@ -118,8 +135,13 @@ export class AlgorandClient {
return this._accountManager
}

/** Methods for interacting with assets. */
public get asset() {
return this._assetManager
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the bulk functions go in the AssetManager?

@robdmoore
Copy link
Contributor Author

why we decided to support a union of string | TransactionSignerAccount for address fields?

It was so that you could pass in the result of something like const alice = algorand.account.random() in i.e. you can pass in alice and not have to do alice.addr i.e. algorand.send.payment({from: alice, to: bob}) reads much nicer than algorand.send.payment({from: alice.addr, to: bob.addr})

We could remove that and just stick with string of course if we felt it was too confusing...

@robdmoore
Copy link
Contributor Author

Also, I see a lot of changes to the formatting of how we saw "Algos". Personally I think non-plural ALGO is the most common. Ie. "I have 10 ALGO" vs "I have 10 Algos"

It's a tough one because I see it written in different ways everywhere, it's wildly inconsistent. I'm not opposed to just using ALGO though, more than happy with that?

@robdmoore
Copy link
Contributor Author

Should the bulk functions go in the AssetManager?

I thought about that. Maybe that makes sense? I put in account because it was being done in the context of an account, but AccountManager is a really big class now and you could argue either way, so maybe AssetManager is better?

@joe-p
Copy link
Contributor

joe-p commented Jul 4, 2024

It was so that you could pass in the result of something like const alice = algorand.account.random()

This begs the question... why not just have .random return a string? Returning an object with the signer makes sense when we are concerned about legacy interop, but now that we're deprecating legacy utils functions maybe it just makes more sense to return a string? I suppose the question really is where do we expect developers to use the signer function manually rather than using it implicitly through the AlgorandClient

It's a tough one because I see it written in different ways everywhere, it's wildly inconsistent. I'm not opposed to just using ALGO though, more than happy with that?

Yeah I don't have a strong opinion on it but consistency is nice at least within the libs we control. Perhaps we can just do a quick poll in slack to see what everyone prefers and just stick with that everywhere.

I thought about that. Maybe that makes sense? I put in account because it was being done in the context of an account, but AccountManager is a really big class now and you could argue either way, so maybe AssetManager is better?

Yeah I can see the argument either way. I personally leans towards AssetManager but have no objections for AccountManager. Although since AccountManager is already a big class and these are relatively uncommon functions to use, it might make more sense to put under AssetManager just for that reason.

@robdmoore
Copy link
Contributor Author

robdmoore commented Jul 4, 2024

I like the simplicity of returning a string, but it feels very wrong from an object oriented / code semantics perspective. ‘String’ is too generic a type for something that important and it would make it much harder to detect when you’re passing the wrong thing in the wrong place maybe?

agree on the other two. Did you want to raise the poll for algos?

@joe-p
Copy link
Contributor

joe-p commented Jul 4, 2024

I like the simplicity of returning a string, but it feels very wrong from an object oriented / code semantics perspective. ‘String’ is too generic a type for something that important and it would make it much harder to detect when you’re passing the wrong thing in the wrong place maybe?

I agree but also think that's just the nature of nominal type systems. I'm not convinced it's worth creating an object just for this purpose.

agree on the other two. Did you want to raise the poll for algos?

Just posted in slack 👍

docs/capabilities/algorand-client.md Outdated Show resolved Hide resolved
docs/capabilities/account.md Outdated Show resolved Hide resolved
docs/capabilities/asset.md Outdated Show resolved Hide resolved
docs/capabilities/asset.md Outdated Show resolved Hide resolved
src/types/algorand-client.ts Outdated Show resolved Hide resolved
…of transaction modules

* Collapsed the second object in algorand.send.type(params, *executeOptions*) to combine into params and make it easier to use
* Added `algorand.client.getTestNetDispenserFromEnvironment`
* Added `algorand.account.assetBulkOptIn`
* Added `algorand.account.assetBulkOptOut`
* Added `algorand.account.ensureFunded`
* Added `algorand.account.ensureFundedFromEnvironment`
* Added `algorand.account.ensureFundedFromTestNetDispenserApi`
* Added `algorand.send/transaction.rekey`
* Added `algorand.send/transaction.assetOptOut`
Added:
* `AssetManager` class and `algorand.asset.getById()`
* `indexer` export off of `@algorandfoundation/algokit-utils` as the future home of all indexer methods

Changed:
* Order of `algorand.account.rekeyed()` parameters to be `rekeyed(sender, signer)` since it conceptually makes more sense (the sender is rekeyed so should come first)
* All microAlgo return values from `algorand.account.getInformation()` now return an `AlgoAmount`, renamed `amount` to `balance` and `round` to `validAsAtRound` (which is now a `bigint` for broader consistency)
* Return value of `algorand.send.assetCreate` now includes `{ assetId: bigint }`

Deprecated:
* `algokit.createAsset`
* `algokit.assetOptIn`
* `algokit.assetOptOut`
* `algokit.assetBulkOptIn`
* `algokit.assetBulkOptOut`
* `algokit.ensureFunded`
* `algokit.transferAsset`
* `algokit.rekeyAccount`
* `algokit.transferAlgos`
…`AccountManager`

Added:
* `algorand.account.rekeyAccount()`

Removed:
* `algorand.send.rekey()`
…, asset, dispenser client, indexer, testing, transfer
Moved account.assetBulkOptIn -> asset.bulkOptIn
Moved account.assetBulkOptOut -> asset.bulkOptOut
Moved account.getAssetInformation -> asset.getAccountInformation
Fixed other miscellaneous issues
@robdmoore
Copy link
Contributor Author

Regardless of whether we decide to do string or not, it makes sense to decouple that from this PR since it's a much wider / bigger / unrelated change.

I also didn't change rekeyAccount to rekeyAddress because there are many other things that tie account = single address, that's a broader change that will somehow need to be incorporated into the Algorand ecosystem with thought to avoid confusion.

Otherwise incorporated all the other feedback.

…ual transactions

refactor: Refactored AlgorandClient to have separate classes for `send` and `transaction`
refactor: Refactored legacyTransactionBridge to not have a dependency of AlgorandClient
src/transaction/legacy-bridge.ts Outdated Show resolved Hide resolved
src/transaction/transaction.ts Show resolved Hide resolved
src/transfer/transfer-algos.ts Show resolved Hide resolved
src/types/algorand-client-sender.ts Outdated Show resolved Hide resolved
export type SendSingleTransactionResult = SendAtomicTransactionComposerResults & ConfirmedTransactionResult

/** Orchestrates sending transactions for `AlgorandClient`. */
export class AlgorandClientSender {
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 adjust the name to be more consistent with the creator. In that case it would become AlgorandClientTransactionSender.

src/types/algorand-client-transaction-creator.ts Outdated Show resolved Hide resolved
src/types/algorand-client-transaction-creator.ts Outdated Show resolved Hide resolved
src/types/algorand-client-transaction-creator.ts Outdated Show resolved Hide resolved
src/types/algorand-client-transaction-creator.ts Outdated Show resolved Hide resolved
@robdmoore robdmoore merged commit 2aebcfd into main Aug 28, 2024
2 checks passed
@robdmoore robdmoore deleted the deprecate-2 branch August 28, 2024 10:55
robdmoore added a commit that referenced this pull request Aug 28, 2024
Breaking changes:
* Renamed `AlgokitComposer` to `AlgoKitComposer` to match AlgoKit naming conventions
* Collapsed the second object in algorand.send.type(params, *executeOptions*) to combine into params and make it easier to use based on devrel feedback
* Order of `algorand.account.rekeyed()` parameters to be `rekeyed(sender, signer)` since it conceptually makes more sense (the sender is rekeyed so should come first)
* All microAlgo return values from `algorand.account.getInformation()` now return an `AlgoAmount`, renamed `amount` to `balance` and `round` to `validAsAtRound` (which is now a `bigint` for broader consistency)
* Renamed `algorand.account.getAssetInformation` to `algorand.asset.getAccountInformation`

Added:
* Return value of `algorand.send.assetCreate` now includes `{ assetId: bigint }`
* Up to date documentation for rekeyAccount, AlgorandClient, asset, dispenser client, indexer, testing, transfer
* Up to date documentation for how to refer to an Algo amount (Algo (not plural) in general and ALGO (not plural) when referring to a specific amount)
* `AssetManager` class and `algorand.asset.getById()`, `algorand.asset.bulkOptIn`, and `algorand.asset.bulkOptOut`
* `indexer` export off of `@algorandfoundation/algokit-utils` as the future home of all indexer methods
* Added `algorand.client.getTestNetDispenserFromEnvironment`
* Added `algorand.account.assetBulkOptIn`
* Added `algorand.account.assetBulkOptOut`
* Added `algorand.account.ensureFunded`
* Added `algorand.account.ensureFundedFromEnvironment`
* Added `algorand.account.ensureFundedFromTestNetDispenserApi`
* Added `algorand.account.rekeyAccount`
* Added `algorand.send/transaction.assetOptOut`
* Added `buildTransactions` method to `AlgoKitComposer` so you can build transactions without needing to register a signer
* Added `.algo` and `.microAlgo` methods/properties in place of the plural version for `AlgoAmount` to reflect the current guidance on how to represent Algo amounts, kept previous versions of those methods for now to avoid the breaking change

Deprecated the following in favour of AlgorandClient functionality:
* `algokit.createAsset`
* `algokit.assetOptIn`
* `algokit.assetOptOut`
* `algokit.assetBulkOptIn`
* `algokit.assetBulkOptOut`
* `algokit.ensureFunded`
* `algokit.transferAsset`
* `algokit.rekeyAccount`
* `algokit.transferAlgos`

BREAKING CHANGE: Numerous

---------

Co-authored-by: Neil Campbell <[email protected]>
@robdmoore robdmoore mentioned this pull request Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants